Production updates

master
bleeson 2024-07-05 15:08:22 -07:00
parent bb8cf98dbb
commit 5c4b689a16
5 changed files with 229 additions and 498 deletions

View File

@ -1,19 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Consume a 846 file from 3PLs, and translate into a Consume a 846 file from 3PLs, and translate into a
inventory comparison report that could be used as a stock count? inventory comparison report
For Shadex we also need to reply with a 997 For Shadex we also need to reply with a 997
947 is warehouse advice, to alert us of damages or amount changes from something
like a count
""" """
#what about serial numbers?
#status on L line?
#remove negative line, needs to look up stocou? not sure.
# pylint: disable=too-many-instance-attributes
import dataclasses
import datetime import datetime
import decimal
import functools
import pathlib import pathlib
import re import re
import shutil import shutil
@ -22,6 +14,7 @@ import smtplib
import pprint import pprint
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText from email.mime.text import MIMEText
import records # type: ignore import records # type: ignore
@ -33,9 +26,11 @@ THIS_DIRECTORY = pathlib.Path(__file__).parent
X12_DIRECTORY = THIS_DIRECTORY / "incoming" X12_DIRECTORY = THIS_DIRECTORY / "incoming"
IMPORTS_DIRECTORY = THIS_DIRECTORY / "x3_imports" IMPORTS_DIRECTORY = THIS_DIRECTORY / "x3_imports"
EDI_997_DIRECTORY = THIS_DIRECTORY / "997_processing" EDI_997_DIRECTORY = THIS_DIRECTORY / "997_processing"
EDI_846_ATTACHMENTS = THIS_DIRECTORY / "846_reports"
EDI_846_ATTACHMENTS_ARCHIVE = EDI_846_ATTACHMENTS / "archive"
SHANDEX_846_FILENAME_RE = re.compile( SHANDEX_846_FILENAME_RE = re.compile(
r"\A 846_YAMAMOTOYAMA_ \S+ [.]edi \Z", re.X | re.M | re.S r"\A 846_STASH-YAMAMOTOYAMA_ \S+ [.]edi \Z", re.X | re.M | re.S
) )
SHANDEX_STATUS = { SHANDEX_STATUS = {
@ -49,11 +44,61 @@ def main():
""" """
Do it! Do it!
""" """
#read in the information from Shandex and store it
for edi_filename in X12_DIRECTORY.iterdir(): for edi_filename in X12_DIRECTORY.iterdir():
if SHANDEX_846_FILENAME_RE.match(edi_filename.name): if SHANDEX_846_FILENAME_RE.match(edi_filename.name):
process_file(edi_filename) shandex_inventory=process_file(edi_filename)
# file moved to 997 processing folder to be sent later # file moved to 997 processing folder to be sent later
shutil.move(edi_filename, EDI_997_DIRECTORY / edi_filename.name) #shutil.move(edi_filename, EDI_997_DIRECTORY / edi_filename.name)
#get stock information about WON and store it
#pass date from EDI so we can subtract newer stock movements?
x3_won_inventory=get_x3_won_inventory()
#write out an excel file with the stock from Shandex with X3 next to it, then include anything missing
compare_inventory(shandex_inventory, x3_won_inventory)
stock_count_alert()
def compare_inventory(shandex_inventory, x3_inventory):
today = datetime.datetime.today()
today = today.strftime('%Y-%m-%d')
with open(EDI_846_ATTACHMENTS / f'inventory_comparison_{today}.csv', 'w', newline='') as outfile:
outfile.write(','.join(['Site','Item','Description','Lot','X3 qty','Shandex qty']))#header
outfile.write('\n')
for record in x3_inventory:
site = record["STOFCY_0"]
item = record["ITMREF_0"]
des = record["ITMDES1_0"]
lot = record["LOT_0"]
qty = str(record["QTY"])
outfile.write(','.join([site, item, des, lot, qty]))
outfile.write(',')
if item in shandex_inventory:
if lot in shandex_inventory[item]:
outfile.write(str(shandex_inventory[item][lot]))
# pprint.pprint(shandex_inventory[item])
del shandex_inventory[item][lot]
# pprint.pprint(shandex_inventory[item])
if len(shandex_inventory[item]) == 0:
# pprint.pprint('entire del')
# pprint.pprint(shandex_inventory[item])
del shandex_inventory[item]
# pprint.pprint(shandex_inventory[item])
else:
outfile.write('0')#lot not found
else:
outfile.write('0')#item not found
outfile.write('\n')
#write the rest of shandex inventory
if len(shandex_inventory) > 0:
outfile.write('Shandex only')
outfile.write('\n')
for item in shandex_inventory:
# pprint.pprint(item)
for lot in shandex_inventory[item]:
# pprint.pprint(lot)
qty = str(shandex_inventory[item][lot])
outfile.write(','.join([item, lot, qty]))
outfile.write('\n')
def tokens_from_edi_file( def tokens_from_edi_file(
@ -68,9 +113,8 @@ def tokens_from_edi_file(
if fields[0] in { if fields[0] in {
"ISA", "ISA",
"GS" "GS"
"N1", "ST",
"N9", "RED",
"SE",
"GE", "GE",
"IEA" "IEA"
}: }:
@ -78,34 +122,107 @@ def tokens_from_edi_file(
yield fields yield fields
def gtin_lookup(gtin): def get_x3_won_inventory():
with yamamotoyama.get_connection('test') as db_connection:#todo remove 'test' #TODO correct the dates used in stock_issues?
with yamamotoyama.get_connection() as db_connection:
return db_connection.query( return db_connection.query(
"""
with stock_issues as (
select
STJ.STOFCY_0,
STJ.ITMREF_0,
STJ.LOT_0,
sum(STJ.QTYSTU_0) [QTYSTU_0]
from PROD.STOJOU STJ
where
STJ.STOFCY_0 = 'WON'
and STJ.IPTDAT_0 between getdate()-1 and getdate()
group by
STJ.STOFCY_0,
STJ.ITMREF_0,
STJ.LOT_0
)
select
SLF.STOFCY_0,
SLF.ITMREF_0,
ITM.ITMDES1_0,
SLF.LOT_0,
cast(sum(SLF.AAACUMQTY_0 + SLF.QQQCUMQTY_0 + SLF.RRRCUMQTY_0 - coalesce(stock_issues.QTYSTU_0,0)) as integer) as QTY,
SLF.AVC_0
from PROD.STOLOTFCY SLF
join PROD.ITMMASTER ITM on
SLF.ITMREF_0 = ITM.ITMREF_0
left join stock_issues
on SLF.ITMREF_0 = stock_issues.ITMREF_0
and SLF.STOFCY_0 = stock_issues.STOFCY_0
and SLF.LOT_0 = stock_issues.LOT_0
where
SLF.STOFCY_0 = 'WON'
group by
SLF.STOFCY_0,
SLF.ITMREF_0,
ITM.ITMDES1_0,
SLF.LOT_0,
SLF.AVC_0
order by 1, 2
""",
#startdate=edi_date,
).all()
def gtin_lookup(gtin):
with yamamotoyama.get_connection() as db_connection:
itmref = db_connection.query(
""" """
select select
[ITM].[ITMREF_0], [ITM].[ITMREF_0],
[ITM].[ITMDES1_0], [ITM].[ITMDES1_0],
[ITM].[EANCOD_0], [ITM].[EANCOD_0],
[ITM].[ZCASEUPC_0] [ITM].[ZCASEUPC_0]
from [FY23TEST].[ITMMASTER] [ITM]--TODO change back to [PROD] from [PROD].[ITMMASTER] [ITM]
join [FY23TEST].[ITMFACILIT] [ITF] join [PROD].[ITMFACILIT] [ITF]
on [ITM].[ITMREF_0] = [ITF].[ITMREF_0] on [ITM].[ITMREF_0] = [ITF].[ITMREF_0]
and [ITF].[STOFCY_0] = 'WON' and [ITF].[STOFCY_0] = 'WON'
where where
[ITM].[ZCASEUPC_0] = :zcaseupc replace([ITM].[ZCASEUPC_0],' ','') = :zcaseupc
""",
zcaseupc=gtin,
).first()
if itmref is None:
itmref = db_connection.query(
"""
select
[ITM].[ITMREF_0],
[ITM].[ITMDES1_0],
[ITM].[EANCOD_0],
[ITM].[ZCASEUPC_0]
from [PROD].[ITMMASTER] [ITM]
join [PROD].[ITMFACILIT] [ITF]
on [ITM].[ITMREF_0] = [ITF].[ITMREF_0]
and [ITF].[STOFCY_0] = 'WON'
where
replace([ITM].[EANCOD_0],' ','') = :zcaseupc
""", """,
zcaseupc=gtin, zcaseupc=gtin,
).first()["ITMREF_0"] ).first()["ITMREF_0"]
else:
itmref = itmref["ITMREF_0"]
return itmref
def stock_movement_alert(itmref, qty, lot, status): def stock_count_alert():
msg = MIMEMultipart() msg = MIMEMultipart()
msg['Subject'] = 'New Stock Change from Shandex' msg['Subject'] = 'New Stock Count from Shandex'
msg['Precedence'] = 'bulk' msg['Precedence'] = 'bulk'
msg['From'] = 'x3report@stashtea.com' msg['From'] = 'x3report@stashtea.com'
msg['To'] = 'bleeson@stashtea.com'#TODO correct receipientscares msg['To'] = 'bleeson@stashtea.com'#TODO correct receipientscares
emailtext = f'Item: {itmref}\nQty: {qty}\nLot: {lot}\nStatus: {DAMAGE_CODE_MAPPING[status]}\nReason: {DAMAGE_CODE_DESCRIPTIONS_MAPPING[status]}' emailtext = f'Attached.'
msg.attach(MIMEText(emailtext, 'plain')) msg.attach(MIMEText(emailtext, 'plain'))
for file in EDI_846_ATTACHMENTS.iterdir():
if file.name.endswith('.csv'):
part = MIMEApplication(open(file, 'rb').read())
part['Content-Disposition'] = f'attachment; filename="{file.name}"'
msg.attach(part)
shutil.move(file, EDI_846_ATTACHMENTS_ARCHIVE / file.name)
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as smtp: 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.login(user='x3reportmk2@yamamotoyama.com', password=r'n</W<7fr"VD~\2&[pZc5')
smtp.send_message(msg) smtp.send_message(msg)
@ -115,450 +232,52 @@ 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.
""" """
warehouse_stockchange = StockChange() shandex_inventory = {} #all inventory
vcrlin = 0 product = ''
lot = ''
qty = 0
for fields in tokens_from_edi_file(edi_filename): for fields in tokens_from_edi_file(edi_filename):
if fields[0] == "G62": if fields[0] == "BIA":
iptdat = fields[2] advice_date = fields[4]
warehouse_stockchange.header.iptdat = datetime.datetime.strptime( if fields[0] == 'LIN':
iptdat, "%Y%m%d" if product != '': #check loop entry
).date() if product not in shandex_inventory: #if we haven't seen the product yet add it
if fields[0] == 'W15': # pprint.pprint('product was not found')
transaction_number = fields[2] shandex_inventory[product] = {lot : qty}
if fields[0] == "W19": # pprint.pprint(shandex_inventory)
vcrlin += 1000 else: #we've seen this product, have we seen the lot
# W19*AV*35*CA**UK*10077652082651***03022026C if lot not in shandex_inventory[product]:#if not, add it
_, status, qty, uom, _, _, gtin, _, _, lot = fields[:10] shandex_inventory[product][lot] = qty
else:
shandex_inventory[product][lot] += qty #if we have add to it
# pprint.pprint('product: ' + product)
# pprint.pprint('lot: ' + lot)
# pprint.pprint('qty: ' + str(qty))
#LIN**SK*077652972160*LT*31052026A
gtin = fields[3]
lot = fields[5]
product = gtin_lookup(gtin) product = gtin_lookup(gtin)
stock_movement_alert(product, qty, lot, status) qty = 0
if status in EMAIL_ONLY_CODES: if fields[0] == "QTY":#product should already exist
return # QTY*33*0
warehouse_stockchange.header.vcrdes = DAMAGE_CODE_DESCRIPTIONS_MAPPING[status] # QTY*20*16
subdetail = StockChangeSubDetail( # QTY*QH*0
qtypcu=int(qty), qty += int(fields[2])
qtystu=int(qty), if fields[0] == "SE":#end of file
sta=DAMAGE_CODE_MAPPING[status], # pprint.pprint('final add')
pcu=uom # pprint.pprint(shandex_inventory)
) # pprint.pprint('product: ' + product)
detail_line = StockChangeDetail( # pprint.pprint('lot: ' + lot)
vcrlin=vcrlin, # pprint.pprint('qty: ' + str(qty))
itmref=product, if product is not None: #check loop entry
pcu=uom, if product not in shandex_inventory: #if we haven't seen the product yet add it
sta=DAMAGE_CODE_SOURCE_MAPPING[status], shandex_inventory[product] = {lot : qty}
lot=lot else: #we've seen this product, have we seen the lot
) if lot not in shandex_inventory[product]:#if not, add it
warehouse_stockchange.append( shandex_inventory[product][lot] = qty
detail_line,
subdetail,
)
time_stamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
with yamamotoyama.x3_imports.open_import_file(
IMPORTS_DIRECTORY / f"ZSCS_{transaction_number}_{time_stamp}.dat"
) as import_file:
warehouse_stockchange.output(import_file)
@dataclasses.dataclass
class StockChangeSubDetail:
"""
Information that goes onto a stockchange sub-detail line, taken from ZPTHI template.
"""
pcu: str = ""
qtypcu: int = 0
qtystu: int = 0
loc: str = ""
sta: str = "A"
# def stojous(self, shipment, item) -> typing.List[str]:
# """
# Convert grouped lot quantities into individual STOJOU records to fit on stockchange
# """
# with yamamotoyama.get_connection('test') as database: #todo remove 'test'
# details = (
# database.query(
# """
# select
# 'S',
# 'A',
# [STJ].[PCU_0],
# cast(cast(-1*[STJ].[QTYSTU_0] as int) as nvarchar),
# [STJ].[LOT_0],
# '',
# ''
# from [FY23TEST].[STOJOU] [STJ] --TODO change to PROD
# where
# [STJ].[VCRNUM_0] = :sdhnum
# and [STJ].[ITMREF_0] = :itmref
# and [STJ].[LOT_0] = :lot
# and [STJ].[TRSTYP_0] = 4
# """,
# sdhnum=shipment,
# itmref=item,
# lot=self.lot,
# )
# .all()
# )
# return details
def convert_to_strings(self) -> typing.List[str]:
"""
Convert to strings for X3 import writing.
"""
def fix_uom(uom):
x3_uom = ''
if uom == 'CA':
x3_uom = 'CS'
else: else:
x3_uom = uom shandex_inventory[product][lot] += qty #if we have add to it
return x3_uom return shandex_inventory
return yamamotoyama.x3_imports.convert_to_strings(
[
"S",
fix_uom(self.pcu),
self.qtypcu,
self.qtystu,
self.loc,
self.sta,
]
)
@dataclasses.dataclass
class StockChangeDetail:
"""
Information that goes on a stockchange detail line, taken from ZPTHI template.
"""
vcrlin: int = 0
itmref: str = ""
pcu: str = ""
pcustucoe: int = 1 #does this need a lookup?
sta: str = "A" #todo this needs to flip based on the transaction A > R, A > Q, what about Q > A?
loctyp: str = ""
loc: str = ""
lot: str = ""
slo: str = ""
sernum: str = ""
palnum: str = ""
ctrnum: str = ""
qlyctldem: str= ""
owner: str = "WON"
subdetails: typing.List[StockChangeSubDetail] = dataclasses.field(
default_factory=list
)
def palnum_lookup(self, itmref, lot, status):
"""
Pick a palnum from X3 using the lot, location, and status
It matters which one we use, best attempt is to get the largest one available
"""
with yamamotoyama.get_connection('test') as db_connection:#todo remove 'test'
return db_connection.query(
"""
select top 1
[STO].[STOFCY_0],
[STO].[ITMREF_0],
[STO].[LOT_0],
[STO].[PALNUM_0],
[STO].[QTYSTU_0]
from [FY23TEST].[STOCK] [STO] --TODO change to PROD
where
[STO].[ITMREF_0] = :itmref
and [STO].[STOFCY_0] = 'WON'
and [STO].[LOT_0] = :lot
and [STO].[STA_0] = :status
order by
[STO].[QTYSTU_0] desc
""",
itmref=itmref,
lot=lot,
status=status
).first()["PALNUM_0"]
def gtin_lookup(self, gtin):
with yamamotoyama.get_connection('test') as db_connection:#todo remove 'test'
return db_connection.query(
"""
select
[ITM].[ITMREF_0],
[ITM].[ITMDES1_0],
[ITM].[EANCOD_0],
[ITM].[ZCASEUPC_0]
from [FY23TEST].[ITMMASTER] [ITM]--TODO change back to [PROD]
join [FY23TEST].[ITMFACILIT] [ITF]
on [ITM].[ITMREF_0] = [ITF].[ITMREF_0]
and [ITF].[STOFCY_0] = 'WON'
where
[ITM].[ZCASEUPC_0] = :zcaseupc
""",
zcaseupc=gtin,
).first()["ITMREF_0"]
def append(self, subdetail: StockChangeSubDetail):
"""
Add subdetail
"""
subdetail.pcu = self.pcu
self.subdetails.append(subdetail)
def check_subdetail_qty(self):
"""
Check for shortages by totaling up subdetail quantities.
"""
total_cases = 0
for subdetail in self.subdetails:
total_cases -= subdetail.qtypcu
return abs(total_cases)
def convert_to_strings(self) -> typing.List[str]:
"""
Convert to strings for X3 import writing.
"""
def fix_uom(uom):
x3_uom = ''
if uom == 'CA':
x3_uom = 'CS'
else:
x3_uom = uom
return x3_uom
self.qty = self.check_subdetail_qty()
return yamamotoyama.x3_imports.convert_to_strings(
[
"L",
self.vcrlin,
self.itmref,
fix_uom(self.pcu),
self.pcustucoe,
self.sta,
self.loctyp,
self.loc,
self.lot,
self.slo,
self.sernum,
self.palnum_lookup(self.itmref, self.lot, self.sta),
self.ctrnum,
self.qlyctldem,
self.owner
]
)
def __eq__(self, item: typing.Any) -> bool:
"""
Test for equality
"""
if isinstance(item, str):
return self.itmref == item
if isinstance(item, StockChangeDetail):
return self.itmref == item.itmref
return False
# def fill(self):#not needed for stockchanges
# """
# Set soplin & itmdes from itmref & sohnum
# """
# def get() -> records.Record:
# with yamamotoyama.get_connection() as database:
# how_many = (
# database.query(
# """
# select
# count(*) as [how_many]
# from [PROD].[SORDERP] as [SOP]
# where
# [SOP].[SOHNUM_0] = :sohnum
# and [SOP].[ITMREF_0] = :itmref
# """,
# sohnum=self.sohnum,
# itmref=self.itmref,
# )
# .first()
# .how_many
# )
# if how_many == 1:
# return database.query(
# """
# select top 1
# [SOP].[SOPLIN_0]
# ,[SOP].[ITMDES1_0]
# ,[SOP].[SAU_0]
# from [PROD].[SORDERP] as [SOP]
# where
# [SOP].[SOHNUM_0] = :sohnum
# and [SOP].[ITMREF_0] = :itmref
# order by
# [SOP].[SOPLIN_0]
# """,
# sohnum=self.sohnum,
# itmref=self.itmref,
# ).first()
# result = get()
# self.soplin = result.SOPLIN_0
# self.itmdes = result.ITMDES1_0
# self.sau = result.SAU_0
@dataclasses.dataclass
class StockChangeHeader:
"""
Information that goes on a stockchange header, taken from ZSCS template.
"""
vcrnum: str = ""
stofcy: str = "WON"
iptdat: datetime.date = datetime.date(1753, 1, 1)
vcrdes: str = ""
pjt: str = ""
trsfam: str = "CHX"
def convert_to_strings(self) -> typing.List[str]:
"""
Convert to X3 import line
"""
return yamamotoyama.x3_imports.convert_to_strings(
[
"E",
self.vcrnum,
self.stofcy,
self.iptdat.strftime("%Y%m%d"),
self.vcrdes,
self.pjt,
self.trsfam,
]
)
class StockChangeDetailList:
"""
List of stockchange details
"""
_details: typing.List[StockChangeDetail]
_item_set: typing.Set[str]
def __init__(self):
self._details = []
self._item_set = set()
def append(
self,
stockchange_detail: StockChangeDetail,
stockchange_subdetail: StockChangeSubDetail,
):
"""
Append
"""
itmref = stockchange_detail.itmref
if itmref in self._item_set:
for detail in self._details:
if detail == itmref:
detail.subdetails.append(stockchange_subdetail)
return
self._item_set.add(itmref)
#stockchange_detail.fill()
stockchange_detail.append(stockchange_subdetail)
self._details.append(stockchange_detail)
def __iter__(self):
return iter(self._details)
class StockChange:
"""
Warehouse stockchange, both header & details
"""
header: StockChangeHeader
details: StockChangeDetailList
_sdhnum: str
def __init__(self):
self.header = StockChangeHeader()
self._sdhnum = ""
self.details = StockChangeDetailList()
def append(
self,
stockchange_detail: StockChangeDetail,
stockchange_subdetail: StockChangeSubDetail,
):
"""
Add detail information.
"""
self.details.append(stockchange_detail, stockchange_subdetail)
@property
def sdhnum(self):
"""
shipment number
"""
return self._sdhnum
@sdhnum.setter
def sdhnum(self, value: str):
if self._sdhnum != value:
self._sdhnum = value
if value:
self._fill_info_from_shipment()
# def _get_shipment_from_x3(self) -> records.Record:
# """
# Fetch shipment from X3 database.
# """
# with yamamotoyama.get_connection('test') as db_connection:#todo remove 'test'
# return db_connection.query(
# """
# select
# [SDH].[STOFCY_0],
# [SDH].[SDHNUM_0],
# [SDH].[SALFCY_0],
# [SDH].[BPCORD_0],
# [SDH].[CUR_0],
# [SDH].[SOHNUM_0]
# from [FY23TEST].[SDELIVERY] [SDH]--TODO change back to [PROD]
# where
# [SDH].[SDHNUM_0] = :shipment
# """,
# shipment=self.sdhnum,
# ).first()
# def _fill_info_from_shipment(self):
# """
# When we learn the SOHNUM, we can copy information from the sales order.
# """
# result = self._get_shipment_from_x3()
# self.header.stofcy = result.STOFCY_0
# self.header.sdhnum = result.SDHNUM_0
# self.header.salfcy = result.SALFCY_0
# self.header.bpcord = result.BPCORD_0
# self.header.cur = result.CUR_0
# self.header.sohnum = result.SOHNUM_0
def output(self, import_file: typing.TextIO):
"""
Output entire order to import_file.
"""
output = functools.partial(
yamamotoyama.x3_imports.output_with_file, import_file
)
output(self.header.convert_to_strings())
for detail in self.details:
output(detail.convert_to_strings())
for subdetail in detail.subdetails:
#shipment = detail.sdhnum
#item = detail.itmref
output(subdetail.convert_to_strings())
# for record in subdetail.stojous(shipment, item):
# output(subdetail.convert_to_strings())
# output(record)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -69,6 +69,18 @@ X3_CUSTOMER_MAPPING = {
'JIVA1000_JIVABC' : 'JIVA0002', 'JIVA1000_JIVABC' : 'JIVA0002',
'WELL1000_WELL' : 'WELL0002', 'WELL1000_WELL' : 'WELL0002',
'WELL1000_WELCAL' : 'WELL0003', 'WELL1000_WELCAL' : 'WELL0003',
'AMAZ1200_YYC4' : 'AMAZ0210',
'AMAZ1200_YVR2' : 'AMAZ0014',
'AMAZ1200_YYZ4' : 'AMAZ0049',
'AMAZ1200_YXU1' : 'AMAZ0189',
'AMAZ1200_YOW3' : 'AMAZ0176',
'PARA1100_0000' : 'PARA0004',
'AMAZ1200_YVR4' : 'AMAZ0099',
'AMAZ1200_YHM1' : 'AMAZ0169',
'AMAZ1200_YYZ7' :'AMAZ0100',
'PURI1000_PURIBC' : 'PURI0003',
'PURI1000_PURIAB' : 'PURI0004',
'AMAZ1200_YEG2' : 'AMAZ0179',
} }
def main(): def main():

View File

@ -42,7 +42,7 @@ def main():
""" """
Do it! Do it!
""" """
with yamamotoyama.get_connection() as database: with yamamotoyama.get_connection('test') as database:
shipments = list(get_shipments(database)) shipments = list(get_shipments(database))
for shipment in shipments: for shipment in shipments:
write_943(database, shipment) write_943(database, shipment)
@ -127,7 +127,7 @@ def write_943(database: records.Connection, shipment: str):
with database.transaction() as _: with database.transaction() as _:
database.query( database.query(
""" """
update [PROD].[SDELIVERY] update [FY23TEST].[SDELIVERY]
set [XX4S_943RDY_0] = 1 set [XX4S_943RDY_0] = 1
where [SOHNUM_0] = :shipment where [SOHNUM_0] = :shipment
""", """,
@ -136,7 +136,7 @@ def write_943(database: records.Connection, shipment: str):
order = get_order_for_shipment(database, shipment) order = get_order_for_shipment(database, shipment)
database.query( database.query(
""" """
update [PROD].[SORDER] update [FY23TEST].[SORDER]
set [XX4S_UDF2_0] = :sent_message set [XX4S_UDF2_0] = :sent_message
where [SOHNUM_0] = :order where [SOHNUM_0] = :order
""", """,
@ -153,7 +153,7 @@ def get_shipment_destination(database: records.Connection, shipment: str) -> str
""" """
select select
[SDH].[BPCORD_0] [SDH].[BPCORD_0]
from [PROD].[SDELIVERY] as [SDH] from [FY23TEST].[SDELIVERY] as [SDH]
where where
[SDH].[SDHNUM_0] = :shipment [SDH].[SDHNUM_0] = :shipment
""", """,
@ -172,7 +172,7 @@ def get_order_for_shipment(database: records.Connection, shipment: str) -> str:
""" """
select select
[SDH].[SOHNUM_0] [SDH].[SOHNUM_0]
from [PROD].[SDELIVERY] as [SDH] from [FY23TEST].[SDELIVERY] as [SDH]
where where
[SDH].[SDHNUM_0] = :shipment [SDH].[SDHNUM_0] = :shipment
""", """,
@ -191,8 +191,8 @@ def get_shipments(database: records.Connection) -> typing.Iterator[str]:
""" """
select select
[SDH].[SDHNUM_0] [SDH].[SDHNUM_0]
from [PROD].[SDELIVERY] as [SDH] from [FY23TEST].[SDELIVERY] as [SDH]
join [PROD].[SORDER] as [SOH] join [FY23TEST].[SORDER] as [SOH]
on [SOH].[SOHNUM_0] = [SDH].[SOHNUM_0] on [SOH].[SOHNUM_0] = [SDH].[SOHNUM_0]
where where
( (
@ -267,7 +267,7 @@ def get_shipment(
,[GROWEI_0] ,[GROWEI_0]
,[CFMFLG_0] ,[CFMFLG_0]
,[SHIDAT_0] ,[SHIDAT_0]
from [PROD].[zyumiddleware_shipment] as [SDH] from [FY23TEST].[zyumiddleware_shipment] as [SDH]
where where
[SDH].[SDHNUM_0] = :shipment [SDH].[SDHNUM_0] = :shipment
""", """,

View File

@ -63,7 +63,7 @@ def validation_alert(sdhnum):
msg['Subject'] = 'New Receipt from Shandex' msg['Subject'] = 'New Receipt from Shandex'
msg['Precedence'] = 'bulk' msg['Precedence'] = 'bulk'
msg['From'] = 'x3report@stashtea.com' msg['From'] = 'x3report@stashtea.com'
#msg['To'] = 'isenn@yamamotoyama.com' msg['To'] = 'isenn@yamamotoyama.com'
msg['CC'] = 'bleeson@stashtea.com' msg['CC'] = 'bleeson@stashtea.com'
emailtext = f'A Shandex receipt for {sdhnum} could not be loaded into X3 because the shipment is not validated.' emailtext = f'A Shandex receipt for {sdhnum} could not be loaded into X3 because the shipment is not validated.'
msg.attach(MIMEText(emailtext, 'plain')) msg.attach(MIMEText(emailtext, 'plain'))

View File

@ -39,7 +39,7 @@ SHANDEX_947_FILENAME_RE = re.compile(
) )
#TODO remove this and have a single production name? why is this one different #TODO remove this and have a single production name? why is this one different
SHANDEX_947_FILENAME_RE = re.compile( SHANDEX_947_FILENAME_RE = re.compile(
r"\A STASH_TEST_947 \S+ [.]edi \Z", re.X | re.M | re.S r"\A 947_QTY_STASH-YAMAMOTOYAMA_ \S+ [.]edi \Z", re.X | re.M | re.S
) )
@ -80,7 +80,7 @@ def main():
if SHANDEX_947_FILENAME_RE.match(edi_filename.name): if SHANDEX_947_FILENAME_RE.match(edi_filename.name):
process_file(edi_filename) process_file(edi_filename)
# file moved to 997 processing folder to be sent later # file moved to 997 processing folder to be sent later
shutil.move(edi_filename, EDI_997_DIRECTORY / edi_filename.name) #shutil.move(edi_filename, EDI_997_DIRECTORY / edi_filename.name)
combine_zscs() combine_zscs()
@ -130,7 +130,7 @@ def tokens_from_edi_file(
def gtin_lookup(gtin): def gtin_lookup(gtin):
with yamamotoyama.get_connection('test') as db_connection:#todo remove 'test' with yamamotoyama.get_connection() as db_connection:
return db_connection.query( return db_connection.query(
""" """
select select
@ -138,8 +138,8 @@ def gtin_lookup(gtin):
[ITM].[ITMDES1_0], [ITM].[ITMDES1_0],
[ITM].[EANCOD_0], [ITM].[EANCOD_0],
[ITM].[ZCASEUPC_0] [ITM].[ZCASEUPC_0]
from [FY23TEST].[ITMMASTER] [ITM]--TODO change back to [PROD] from [PROD].[ITMMASTER] [ITM]
join [FY23TEST].[ITMFACILIT] [ITF] join [PROD].[ITMFACILIT] [ITF]
on [ITM].[ITMREF_0] = [ITF].[ITMREF_0] on [ITM].[ITMREF_0] = [ITF].[ITMREF_0]
and [ITF].[STOFCY_0] = 'WON' and [ITF].[STOFCY_0] = 'WON'
where where
@ -183,7 +183,7 @@ def process_file(edi_filename: pathlib.Path):
product = gtin_lookup(gtin) product = gtin_lookup(gtin)
stock_movement_alert(product, qty, lot, status) stock_movement_alert(product, qty, lot, status)
if status in EMAIL_ONLY_CODES: if status in EMAIL_ONLY_CODES:
return continue
warehouse_stockchange.header.vcrdes = DAMAGE_CODE_DESCRIPTIONS_MAPPING[status] warehouse_stockchange.header.vcrdes = DAMAGE_CODE_DESCRIPTIONS_MAPPING[status]
subdetail = StockChangeSubDetail( subdetail = StockChangeSubDetail(
qtypcu=int(qty), qtypcu=int(qty),
@ -307,7 +307,7 @@ class StockChangeDetail:
Pick a palnum from X3 using the lot, location, and status Pick a palnum from X3 using the lot, location, and status
It matters which one we use, best attempt is to get the largest one available It matters which one we use, best attempt is to get the largest one available
""" """
with yamamotoyama.get_connection('test') as db_connection:#todo remove 'test' with yamamotoyama.get_connection() as db_connection:
result = db_connection.query( result = db_connection.query(
""" """
select top 1 select top 1
@ -316,7 +316,7 @@ class StockChangeDetail:
[STO].[LOT_0], [STO].[LOT_0],
[STO].[PALNUM_0], [STO].[PALNUM_0],
[STO].[QTYSTU_0] [STO].[QTYSTU_0]
from [FY23TEST].[STOCK] [STO] --TODO change to PROD from [PROD].[STOCK] [STO]
where where
[STO].[ITMREF_0] = :itmref [STO].[ITMREF_0] = :itmref
and [STO].[STOFCY_0] = 'WON' and [STO].[STOFCY_0] = 'WON'
@ -335,7 +335,7 @@ class StockChangeDetail:
raise NotImplementedError raise NotImplementedError
def gtin_lookup(self, gtin): def gtin_lookup(self, gtin):
with yamamotoyama.get_connection('test') as db_connection:#todo remove 'test' with yamamotoyama.get_connection() as db_connection:
return db_connection.query( return db_connection.query(
""" """
select select
@ -343,8 +343,8 @@ class StockChangeDetail:
[ITM].[ITMDES1_0], [ITM].[ITMDES1_0],
[ITM].[EANCOD_0], [ITM].[EANCOD_0],
[ITM].[ZCASEUPC_0] [ITM].[ZCASEUPC_0]
from [FY23TEST].[ITMMASTER] [ITM]--TODO change back to [PROD] from [PROD].[ITMMASTER] [ITM]
join [FY23TEST].[ITMFACILIT] [ITF] join [PROD].[ITMFACILIT] [ITF]
on [ITM].[ITMREF_0] = [ITF].[ITMREF_0] on [ITM].[ITMREF_0] = [ITF].[ITMREF_0]
and [ITF].[STOFCY_0] = 'WON' and [ITF].[STOFCY_0] = 'WON'
where where