Production updates
parent
bb8cf98dbb
commit
5c4b689a16
649
edi_846.py
649
edi_846.py
|
@ -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__":
|
||||||
|
|
12
edi_867.py
12
edi_867.py
|
@ -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():
|
||||||
|
|
16
edi_943.py
16
edi_943.py
|
@ -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
|
||||||
""",
|
""",
|
||||||
|
|
|
@ -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'))
|
||||||
|
|
22
edi_947.py
22
edi_947.py
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue