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
"""
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
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 decimal
import functools
import pathlib
import re
import shutil
@ -22,6 +14,7 @@ import smtplib
import pprint
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
import records # type: ignore
@ -33,9 +26,11 @@ THIS_DIRECTORY = pathlib.Path(__file__).parent
X12_DIRECTORY = THIS_DIRECTORY / "incoming"
IMPORTS_DIRECTORY = THIS_DIRECTORY / "x3_imports"
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(
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 = {
@ -49,11 +44,61 @@ def main():
"""
Do it!
"""
#read in the information from Shandex and store it
for edi_filename in X12_DIRECTORY.iterdir():
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
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(
@ -68,9 +113,8 @@ def tokens_from_edi_file(
if fields[0] in {
"ISA",
"GS"
"N1",
"N9",
"SE",
"ST",
"RED",
"GE",
"IEA"
}:
@ -78,34 +122,107 @@ def tokens_from_edi_file(
yield fields
def gtin_lookup(gtin):
with yamamotoyama.get_connection('test') as db_connection:#todo remove 'test'
return db_connection.query(
"""
def get_x3_won_inventory():
#TODO correct the dates used in stock_issues?
with yamamotoyama.get_connection() as db_connection:
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
[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"]
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
[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].[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,
).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['Subject'] = 'New Stock Change from Shandex'
msg['Subject'] = 'New Stock Count from Shandex'
msg['Precedence'] = 'bulk'
msg['From'] = 'x3report@stashtea.com'
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'))
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:
smtp.login(user='x3reportmk2@yamamotoyama.com', password=r'n</W<7fr"VD~\2&[pZc5')
smtp.send_message(msg)
@ -115,450 +232,52 @@ def process_file(edi_filename: pathlib.Path):
"""
Convert a specific EDI file into an import file.
"""
warehouse_stockchange = StockChange()
vcrlin = 0
shandex_inventory = {} #all inventory
product = ''
lot = ''
qty = 0
for fields in tokens_from_edi_file(edi_filename):
if fields[0] == "G62":
iptdat = fields[2]
warehouse_stockchange.header.iptdat = datetime.datetime.strptime(
iptdat, "%Y%m%d"
).date()
if fields[0] == 'W15':
transaction_number = fields[2]
if fields[0] == "W19":
vcrlin += 1000
# W19*AV*35*CA**UK*10077652082651***03022026C
_, status, qty, uom, _, _, gtin, _, _, lot = fields[:10]
if fields[0] == "BIA":
advice_date = fields[4]
if fields[0] == 'LIN':
if product != '': #check loop entry
if product not in shandex_inventory: #if we haven't seen the product yet add it
# pprint.pprint('product was not found')
shandex_inventory[product] = {lot : qty}
# pprint.pprint(shandex_inventory)
else: #we've seen this product, have we seen the lot
if lot not in shandex_inventory[product]:#if not, add it
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)
stock_movement_alert(product, qty, lot, status)
if status in EMAIL_ONLY_CODES:
return
warehouse_stockchange.header.vcrdes = DAMAGE_CODE_DESCRIPTIONS_MAPPING[status]
subdetail = StockChangeSubDetail(
qtypcu=int(qty),
qtystu=int(qty),
sta=DAMAGE_CODE_MAPPING[status],
pcu=uom
)
detail_line = StockChangeDetail(
vcrlin=vcrlin,
itmref=product,
pcu=uom,
sta=DAMAGE_CODE_SOURCE_MAPPING[status],
lot=lot
)
warehouse_stockchange.append(
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:
x3_uom = uom
return x3_uom
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)
qty = 0
if fields[0] == "QTY":#product should already exist
# QTY*33*0
# QTY*20*16
# QTY*QH*0
qty += int(fields[2])
if fields[0] == "SE":#end of file
# pprint.pprint('final add')
# pprint.pprint(shandex_inventory)
# pprint.pprint('product: ' + product)
# pprint.pprint('lot: ' + lot)
# pprint.pprint('qty: ' + str(qty))
if product is not None: #check loop entry
if product not in shandex_inventory: #if we haven't seen the product yet add it
shandex_inventory[product] = {lot : qty}
else: #we've seen this product, have we seen the lot
if lot not in shandex_inventory[product]:#if not, add it
shandex_inventory[product][lot] = qty
else:
shandex_inventory[product][lot] += qty #if we have add to it
return shandex_inventory
if __name__ == "__main__":

View File

@ -69,6 +69,18 @@ X3_CUSTOMER_MAPPING = {
'JIVA1000_JIVABC' : 'JIVA0002',
'WELL1000_WELL' : 'WELL0002',
'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():

View File

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

View File

@ -63,7 +63,7 @@ def validation_alert(sdhnum):
msg['Subject'] = 'New Receipt from Shandex'
msg['Precedence'] = 'bulk'
msg['From'] = 'x3report@stashtea.com'
#msg['To'] = 'isenn@yamamotoyama.com'
msg['To'] = 'isenn@yamamotoyama.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.'
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
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):
process_file(edi_filename)
# 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()
@ -130,7 +130,7 @@ def tokens_from_edi_file(
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(
"""
select
@ -138,8 +138,8 @@ def gtin_lookup(gtin):
[ITM].[ITMDES1_0],
[ITM].[EANCOD_0],
[ITM].[ZCASEUPC_0]
from [FY23TEST].[ITMMASTER] [ITM]--TODO change back to [PROD]
join [FY23TEST].[ITMFACILIT] [ITF]
from [PROD].[ITMMASTER] [ITM]
join [PROD].[ITMFACILIT] [ITF]
on [ITM].[ITMREF_0] = [ITF].[ITMREF_0]
and [ITF].[STOFCY_0] = 'WON'
where
@ -183,7 +183,7 @@ def process_file(edi_filename: pathlib.Path):
product = gtin_lookup(gtin)
stock_movement_alert(product, qty, lot, status)
if status in EMAIL_ONLY_CODES:
return
continue
warehouse_stockchange.header.vcrdes = DAMAGE_CODE_DESCRIPTIONS_MAPPING[status]
subdetail = StockChangeSubDetail(
qtypcu=int(qty),
@ -307,7 +307,7 @@ class StockChangeDetail:
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'
with yamamotoyama.get_connection() as db_connection:
result = db_connection.query(
"""
select top 1
@ -316,7 +316,7 @@ class StockChangeDetail:
[STO].[LOT_0],
[STO].[PALNUM_0],
[STO].[QTYSTU_0]
from [FY23TEST].[STOCK] [STO] --TODO change to PROD
from [PROD].[STOCK] [STO]
where
[STO].[ITMREF_0] = :itmref
and [STO].[STOFCY_0] = 'WON'
@ -335,7 +335,7 @@ class StockChangeDetail:
raise NotImplementedError
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(
"""
select
@ -343,8 +343,8 @@ class StockChangeDetail:
[ITM].[ITMDES1_0],
[ITM].[EANCOD_0],
[ITM].[ZCASEUPC_0]
from [FY23TEST].[ITMMASTER] [ITM]--TODO change back to [PROD]
join [FY23TEST].[ITMFACILIT] [ITF]
from [PROD].[ITMMASTER] [ITM]
join [PROD].[ITMFACILIT] [ITF]
on [ITM].[ITMREF_0] = [ITF].[ITMREF_0]
and [ITF].[STOFCY_0] = 'WON'
where