Mapping ship-to customers.

master
bleeson 2024-05-28 07:50:09 -07:00
parent 7c50f8b6c7
commit eb4d0beac8
1 changed files with 107 additions and 14 deletions

View File

@ -2,6 +2,11 @@
""" """
Consume a 867 file from Shandex, and translate into a Sage X3 Consume a 867 file from Shandex, and translate into a Sage X3
readable file-ZSHIP867. readable file-ZSHIP867.
New changes, need to bring in under ship to customer whenever possible.
Build a mapping file of known customers by matching their address to x3 codes
need to not import a shipment if a customer mapping doesn't exist.
""" """
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
import dataclasses import dataclasses
@ -13,6 +18,9 @@ import re
import shutil import shutil
import typing import typing
import pprint import pprint
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import records # type: ignore import records # type: ignore
@ -25,13 +33,38 @@ IMPORTS_DIRECTORY = THIS_DIRECTORY / "x3_imports"
EDI_997_DIRECTORY = THIS_DIRECTORY / "997_processing" EDI_997_DIRECTORY = THIS_DIRECTORY / "997_processing"
SOURCE_867_FILENAME_RE = re.compile( SOURCE_867_FILENAME_RE = re.compile(
r"\A 867_YAMAMOTOYAMA_ .* [.]edi \Z", re.X | re.M | re.S r"\A 867_STASH-YAMAMOTOYAMA_ .* [.]edi \Z", re.X | re.M | re.S
) )
UOM_MAPPING = { UOM_MAPPING = {
"CA" : "CS", "CA" : "CS",
"EC" : "EA" "EC" : "EA"
} }
#NAME_ADDRESS_CITY_TERRITORY_POSTAL : X3 Customer Code
X3_CUSTOMER_MAPPING = {
'AVRI1000_AVRIQC' : 'AVRI0001',
'BULK1000_BULKAU' : 'BULK0001',
'COOP2000_190148' : 'FEDE0006',
'COOP2000_190149' : 'FEDE0005',
'COOP2000_607S' : 'FEDE0003',
'COOP2000_CAL' : 'FEDE0007',
'HORI1000_HORIBC' : 'HORI0001',
'LOND1000_190005' : 'LOND0001',
'NATI1000_28' : 'LOBL0002',
'NATI1000_34' : 'LOBL0006',
'NATI1000_D022' : 'LOBL0001',
'ONTA1100_ONTAON' : 'ONTA0002',
'OVER1000_5111' : 'OVER0002',
'OVER1000_A24' : 'OVER0004',
'PARA1100_PARABC' : 'PARA0004',
'PSCN1000_PSCBC' : 'PSCN0002',
'PURE1000_PUREON' : 'PURE0004',
'PURI1000_PURION' : 'PURI0002',
'SATA1000_SATAQC' : 'SATA0002',
'UNFI1000_UNFIBC' : 'UNFI0011',
'UNFI1000_UNFION' : 'UNFI0004',
'SAMP1000_0000' : 'YARI0001'
}
def main(): def main():
""" """
@ -45,6 +78,19 @@ def main():
combine_zship867s() combine_zship867s()
def missing_customer_alert(customer_key):
msg = MIMEMultipart()
msg['Subject'] = 'Shandex 867 - Missing X3 Customer'
msg['Precedence'] = 'bulk'
msg['From'] = 'x3report@stashtea.com'
msg['To'] = 'technical-contact@stashtea.com'
emailtext = f'Missing value: {customer_key}'
msg.attach(MIMEText(emailtext, 'plain'))
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as smtp:
smtp.login(user='x3reportmk2@yamamotoyama.com', password=r'n</W<7fr"VD~\2&[pZc5')
smtp.send_message(msg)
def combine_zship867s(): def combine_zship867s():
""" """
Collect all ZSHIP867 imports into a single file for easy import. Collect all ZSHIP867 imports into a single file for easy import.
@ -79,11 +125,9 @@ def tokens_from_edi_file(
fields = record.split("*") fields = record.split("*")
if fields[0] in { if fields[0] in {
"ISA", "ISA",
"GS",
"ST", "ST",
"BPT", "BPT",
"N1",
"PTD",
"REF",
}: }:
continue continue
yield fields yield fields
@ -111,15 +155,53 @@ def process_file(edi_filename: pathlib.Path):
""" """
Convert a specific EDI file into an import file. Convert a specific EDI file into an import file.
""" """
shipping_date = ''
previous_picking_number = ''
warehouse_shipment = WarehouseShipment() warehouse_shipment = WarehouseShipment()
for fields in tokens_from_edi_file(edi_filename): for fields in tokens_from_edi_file(edi_filename):
if fields[0] == "GS":
control_number = fields[5]
warehouse_shipment.header.ylicplate = f'{control_number}'
if fields[0] == "DTM": if fields[0] == "DTM":
date_field = fields[2] shipping_date = fields[2]
if fields[0] == "PTD" and len(fields) > 2:#There is one PTD in the header that is not used
picking_number = fields[5]
warehouse_shipment.header.ylicplate = f'{previous_picking_number}'
if picking_number != previous_picking_number and previous_picking_number != '':
if warehouse_shipment.header.bpdnam != 'Shandex Group':
#pprint.pprint(warehouse_shipment.header.ylicplate)
warehouse_shipment.header.shidat = datetime.datetime.strptime( warehouse_shipment.header.shidat = datetime.datetime.strptime(
date_field, "%Y%m%d") shipping_date, "%Y%m%d")
time_stamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
with yamamotoyama.x3_imports.open_import_file(
IMPORTS_DIRECTORY / f"ZSHIP867_{picking_number}_{time_stamp}.dat"
) as import_file:
warehouse_shipment.output(import_file)
warehouse_shipment = WarehouseShipment()
warehouse_shipment.header.ylicplate = f'{picking_number}'
previous_picking_number = picking_number
if fields[0] =='REF' and fields[1] == 'IL':
picking_number = fields[2]
if fields[0] == "N1" and fields[1] == 'ST':
ship_to_customer = fields[2]
shandex_code_part1 = fields[4]
warehouse_shipment.header.bpdnam = ship_to_customer
if fields[0] == "N1" and fields[1] == 'BY':
shandex_code_part2 = fields[4]
if fields[0] == "N3":
ship_to_address = fields[1]
warehouse_shipment.header.bpdaddlig = ship_to_address
if fields[0] == "N4":
ship_to_city = fields[1]
ship_to_province = fields[2]
ship_to_zip = fields[3]
warehouse_shipment.header.bpdposcod = ship_to_zip
warehouse_shipment.header.bpdcty = ship_to_city
warehouse_shipment.header.bpdsat = ship_to_province
customer_key = warehouse_shipment.create_customer_key(shandex_code_part2, shandex_code_part1)
if customer_key not in X3_CUSTOMER_MAPPING.keys():
pprint.pprint(customer_key + ' not found.')
missing_customer_alert(customer_key)
raise NotImplementedError
else:
warehouse_shipment.header.bpcord = X3_CUSTOMER_MAPPING[customer_key]
if fields[0] == "QTY": if fields[0] == "QTY":
#QTY*39*10*CA #QTY*39*10*CA
_, _, qty_str, uom = fields[:4] _, _, qty_str, uom = fields[:4]
@ -127,14 +209,14 @@ def process_file(edi_filename: pathlib.Path):
if fields[0] == "LIN": if fields[0] == "LIN":
#LIN**VN*10077652082224*LT*09032026C# #LIN**VN*10077652082224*LT*09032026C#
_, _, _, gtin, _, lot = fields[:6] _, _, _, gtin, _, lot = fields[:6]
if fields[0] == "UIT": if fields[0] == "AMT":
#UIT*CA*0.00 #AMT*LP*53.90
_, _, price = fields[:3] _, _, price = fields[:3]
sau = UOM_MAPPING[uom] sau = UOM_MAPPING[uom]
lookup_values = get_product_from_gtin(gtin) lookup_values = get_product_from_gtin(gtin)
itmref = lookup_values['ITMREF_0'] itmref = lookup_values['ITMREF_0']
itmdes = lookup_values['ITMDES1_0'] itmdes = lookup_values['ITMDES1_0']
#pprint.pprint(itmdes)
subdetail = WarehouseShipmentSubDetail( subdetail = WarehouseShipmentSubDetail(
qtypcu=-1 * int(qty_str), qtypcu=-1 * int(qty_str),
lot=lot, lot=lot,
@ -151,9 +233,12 @@ def process_file(edi_filename: pathlib.Path):
), ),
subdetail, subdetail,
) )
#pprint.pprint(warehouse_shipment.header.ylicplate)
warehouse_shipment.header.shidat = datetime.datetime.strptime(
shipping_date, "%Y%m%d")
time_stamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") time_stamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
with yamamotoyama.x3_imports.open_import_file( with yamamotoyama.x3_imports.open_import_file(
IMPORTS_DIRECTORY / f"ZSHIP867_{control_number}_{time_stamp}.dat" IMPORTS_DIRECTORY / f"ZSHIP867_{picking_number}_{time_stamp}.dat"
) as import_file: ) as import_file:
warehouse_shipment.output(import_file) warehouse_shipment.output(import_file)
@ -316,6 +401,7 @@ class WarehouseShipmentHeader:
salfcy: str = "STC" salfcy: str = "STC"
stofcy: str = "WON" stofcy: str = "WON"
sdhnum: str = "" sdhnum: str = ""
bpcinv: str = "SHAN0001"
bpcord: str = "SHAN0001" bpcord: str = "SHAN0001"
bpaadd: str = "BL001" bpaadd: str = "BL001"
cur: str = "CAD" cur: str = "CAD"
@ -399,6 +485,7 @@ class WarehouseShipmentHeader:
self.salfcy, self.salfcy,
self.stofcy, self.stofcy,
self.sdhnum, self.sdhnum,
self.bpcinv,
self.bpcord, self.bpcord,
self.bpaadd, self.bpaadd,
self.cur, self.cur,
@ -548,6 +635,12 @@ class WarehouseShipment:
if value: if value:
self._fill_info_from_so() self._fill_info_from_so()
def create_customer_key(self, part1, part2):
key = (part1 + '_' + part2).replace(' ', '_')
return key
def _get_so_from_x3(self) -> records.Record: def _get_so_from_x3(self) -> records.Record:
""" """
Fetch sales order from X3 database. Fetch sales order from X3 database.