Mapping ship-to customers.
parent
7c50f8b6c7
commit
eb4d0beac8
121
edi_867.py
121
edi_867.py
|
@ -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]
|
||||||
warehouse_shipment.header.shidat = datetime.datetime.strptime(
|
if fields[0] == "PTD" and len(fields) > 2:#There is one PTD in the header that is not used
|
||||||
date_field, "%Y%m%d")
|
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(
|
||||||
|
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.
|
||||||
|
|
Loading…
Reference in New Issue