275 lines
11 KiB
Python
275 lines
11 KiB
Python
# -*- coding: utf-8 -*-
|
|
import pymssql
|
|
from collections import OrderedDict
|
|
from pyjeeves.models import db
|
|
from pyjeeves import logging
|
|
from datetime import date
|
|
# from datetime import datetime
|
|
# from decimal import Decimal
|
|
|
|
logger = logging.getLogger("PyJeeves." + __name__)
|
|
|
|
|
|
class StoredProcedure(OrderedDict):
|
|
__raw_params = {}
|
|
# https://www.mssqltips.com/sqlservertip/1669/generate-a-parameter-list-for-all-sql-server-stored-procedures-and-functions/ # noqa
|
|
query = """SELECT SCHEMA_NAME(SCHEMA_ID) AS [Schema],
|
|
SO.name AS [ObjectName],
|
|
SO.Type_Desc AS [ObjectType (UDF/SP)],
|
|
P.parameter_id AS [ParameterID],
|
|
P.name AS [ParameterName],
|
|
TYPE_NAME(P.user_type_id) AS [ParameterDataType],
|
|
P.max_length AS [ParameterMaxBytes],
|
|
P.is_output AS [IsOutPutParameter]
|
|
FROM sys.objects AS SO
|
|
INNER JOIN sys.parameters AS P
|
|
ON SO.OBJECT_ID = P.OBJECT_ID
|
|
WHERE SO.name LIKE '%Jeeves_Esales_%' OR
|
|
SO.name LIKE '%JAPP_spr_LogTrade_%' AND
|
|
SO.OBJECT_ID IN ( SELECT OBJECT_ID
|
|
FROM sys.objects
|
|
WHERE TYPE IN ('P','FN'))
|
|
ORDER BY [Schema], SO.name, P.parameter_id"""
|
|
|
|
logger.debug("Getting information about stored procedures from database")
|
|
|
|
for param in db.execute(query):
|
|
if param['ObjectName'] not in __raw_params:
|
|
__raw_params[param['ObjectName']] = OrderedDict()
|
|
param_name = param['ParameterName'][1:]
|
|
__raw_params[param['ObjectName']][param_name] = param
|
|
|
|
@classmethod
|
|
def get_params_for(cls, procedure_name):
|
|
rv = OrderedDict()
|
|
for key in cls.__raw_params[procedure_name]:
|
|
param = cls.__raw_params[procedure_name][key]
|
|
if 'int' in param['ParameterDataType'].lower():
|
|
param_type = int
|
|
elif ('money' in param['ParameterDataType'].lower() or
|
|
'decimal' in param['ParameterDataType'].lower() or
|
|
'float' in param['ParameterDataType'].lower() or
|
|
'qty' in param['ParameterDataType'].lower()):
|
|
param_type = float
|
|
else:
|
|
# TODO: Format datetime and perhaps decimal?
|
|
param_type = str
|
|
|
|
if param['IsOutPutParameter'] == 1:
|
|
param_type = pymssql.output(param_type)
|
|
else:
|
|
param_type = param_type()
|
|
|
|
rv[key] = param_type
|
|
|
|
return rv
|
|
|
|
def __init__(self, procedure_name):
|
|
super(StoredProcedure, self).__init__()
|
|
self.procedure = procedure_name
|
|
self.update(StoredProcedure.get_params_for(self.procedure))
|
|
|
|
def _set_output(self, data=(), ret_resultset=False):
|
|
if ret_resultset:
|
|
return data
|
|
if len(self) != len(data):
|
|
raise
|
|
for p, k in enumerate(self):
|
|
if isinstance(self[k], pymssql.output):
|
|
self[k] = data[p]
|
|
return self
|
|
# Should the original object be unmodified? Return a new object:
|
|
# return [(k, data[p]) for p, k in enumerate(self)]
|
|
|
|
def callproc(self, resultset=False):
|
|
return self._set_output(db.callproc(
|
|
self.procedure,
|
|
self.values()),
|
|
resultset)
|
|
|
|
def values(self):
|
|
return [value if value else None
|
|
for value in super(StoredProcedure, self).values()]
|
|
|
|
def __setitem__(self, key, obj):
|
|
if (key in self and type(self[key]) is not type(obj) and
|
|
obj is not None and not isinstance(self[key], pymssql.output)):
|
|
raise TypeError
|
|
super(StoredProcedure, self).__setitem__(key, obj)
|
|
|
|
|
|
class OrderHead(StoredProcedure):
|
|
"""Mapping for the Jeeves_Esales_CreateOrder stored procedure parameters
|
|
webapp031 and WEBAPP003 determines default order status"""
|
|
# TODO: Extend with additional functionlity if desired.
|
|
|
|
def __init__(self, company_no, web_user_name, pers_sign='biz'):
|
|
super(OrderHead, self).__init__('Jeeves_Esales_CreateOrder')
|
|
|
|
self['c_CompanyNo'] = company_no
|
|
|
|
# Some defaults:
|
|
self['c_ForetagKod'] = 1 # Hardcoded to LK
|
|
self['c_PersSign'] = str(pers_sign) # From API profile, or default
|
|
# self['c_OrderType'] = None # Default set by WEBAPP008
|
|
# self['c_TemplateRowID'] = None # No template used
|
|
# self['c_Saljare'] = None # 600 # From API profile, or default
|
|
|
|
# Unique ID added to 'kpw' when invoicing is allowed.
|
|
self['c_webUserName'] = web_user_name
|
|
|
|
# self['LangID'] = 0 # Default to Swedish
|
|
# self['BatchId'] = '' # unused
|
|
|
|
# self['Run_Type'] = None # Could be 'R', but doesn't work
|
|
|
|
# self['Edit'] = None # Custom ordertext, currently not used in procedure
|
|
# self['EditExt'] = None # Custom ordertext, currently not used in procedure
|
|
|
|
# self['Lagstalle'] = None # '1' # Used to override customer default
|
|
# self['OverrideCreditLimit'] = 0 # Set to a char to override credit limit
|
|
# self['OrderNumber'] = pymssql.output(int)
|
|
|
|
def callproc(self):
|
|
try:
|
|
super(OrderHead, self).callproc()
|
|
except pymssql.DatabaseError:
|
|
logger.error("A DatabaseException has been caught. Order could not be created..")
|
|
|
|
# If call succeeded, then order is allowed to be invoiced.
|
|
return self['o_OrderNumber'], bool(self['c_webUserName'])
|
|
|
|
|
|
class OrderRow(StoredProcedure):
|
|
"""Mapping for the Jeeves_Esales_AddOrderRow stored procedure parameters
|
|
AltEnhetKod logic needs to have been added to the procedure"""
|
|
|
|
def __init__(self, company_no, order_no, item_no,
|
|
qty=None, qty_alt_unit=None, alt_unit=None,
|
|
requested_date=None, pers_sign='biz'):
|
|
super(OrderRow, self).__init__('Jeeves_Esales_AddOrderRow')
|
|
|
|
self['c_CompanyNo'] = str(company_no)
|
|
self['c_OrderNumber'] = int(order_no)
|
|
self['c_ItemNo'] = str(item_no)
|
|
self['c_Qty'] = float(qty) if qty else None
|
|
self['c_QtyAltEnh'] = float(qty_alt_unit) if qty_alt_unit else None
|
|
self['c_AltEnhetKod'] = str(alt_unit) if alt_unit else None
|
|
self['c_PersSign'] = str(pers_sign)
|
|
|
|
# Used to set date for delivery (c_OrdBegLevDat) and (c_OrdBerLevDat)
|
|
self['c_RequestedDate'] = (
|
|
requested_date.strftime('%Y%m%d')
|
|
if isinstance(requested_date, date) else requested_date)
|
|
|
|
# Some defaults:
|
|
self['c_ForetagKod'] = 1 # Hardcoded to LK
|
|
# self['OrderNumber'] = 0 # Required, ordernumber to add row to
|
|
# self['webUserName'] = order_head['webUserName']
|
|
# self['CompanyNo'] = order_head['CompanyNo']
|
|
# self['PersSign'] = order_head['PersSign']
|
|
# self['LangID'] = order_head['LangID']
|
|
# self['ItemNo'] = '' # Required, item to create row for
|
|
# self['c_Qty'] = None # Only one of qty or qtyaltenh may be used
|
|
# self['QtyAltEnh'] = None
|
|
# self['RequestedDate'] = '' # unused
|
|
# self['BatchId'] = order_head['BatchId']
|
|
# self['ArtSerieNr'] = '' # unused
|
|
# self['c_OrderType'] = None
|
|
# self['Run_Type'] = None # Could be 'R', but doesn't work
|
|
# self['c_TemplateRowID'] = None # No template used
|
|
# self['Edit'] = None # Custom order row text
|
|
# self['EditExt'] = None # Custom extended order row text
|
|
# self['Lagstalle'] = None # str: use default
|
|
# self['AltEnhetKod'] = '' # Override default alternative unit if desired
|
|
# self['AllocateAvailable'] = 0 # unused
|
|
# self['OverrideCreditLimit'] = 0 # Set to a char to override credit limit
|
|
# self['o_OrderRow'] = pymssql.output(int)
|
|
# self['o_NextQty'] = pymssql.output(float)
|
|
# self['o_NextDate'] = pymssql.output(str)
|
|
# self['o_LastQty'] = pymssql.output(float)
|
|
# self['o_LastDate'] = pymssql.output(str)
|
|
# self['o_AllocatedQty'] = pymssql.output(float)
|
|
# self['o_AllocatedDate'] = pymssql.output(str)
|
|
|
|
def callproc(self):
|
|
try:
|
|
super(OrderRow, self).callproc()
|
|
except pymssql.DatabaseError:
|
|
logger.error("A DatabaseException has been caught. Order row not created.")
|
|
return self['o_OrderRow']
|
|
|
|
|
|
class PlaceOrder(StoredProcedure):
|
|
"""Mapping for the Jeeves_Esales_PlaceOrder stored procedure parameters
|
|
webapp031 and WEBAPP003 determines default order status"""
|
|
|
|
def __init__(self, company_no, order_no, web_user_name=None, payment_method='card', data={}):
|
|
super(PlaceOrder, self).__init__('Jeeves_Esales_PlaceOrder')
|
|
|
|
self['c_CompanyNo'] = str(company_no)
|
|
self['c_OrderNumber'] = int(order_no)
|
|
self['c_kundref2'] = data.get('CustomerContact') # Er ref, kontaktperson
|
|
self['c_kundbestnr'] = data.get('CustomerReference')
|
|
self['c_editext'] = data.get('ExtraText') # Extern text
|
|
self['c_CoName'] = data.get('AddrName')
|
|
self['c_Addr1'] = data.get('AddrCO') # Lev.adress, c/o
|
|
self['c_Addr2'] = data.get('AddrStreet')
|
|
self['c_PostalCode'] = data.get('AddrPostalCode')
|
|
self['c_City'] = data.get('AddrCity')
|
|
self['c_CountryCode'] = data.get('AddrCountry', 'SE') # Ex: SE, FI etc.
|
|
self['c_godsmarke1'] = data.get('ShippingInfo')
|
|
self['c_godsmarke2'] = data.get('InternalInfo') # Kundspecifikt
|
|
|
|
notify_info = NotifyInfo(company_no).callproc()
|
|
self['c_TA_MailNotified'] = data.get('ShippingEmail', notify_info.get('email'))
|
|
self['c_TA_PhonNotifiedNo'] = data.get('ShippingPhone', notify_info.get('phone'))
|
|
self['c_TA_SMSNotifiedNo'] = data.get('ShippingSMS', notify_info.get('sms'))
|
|
|
|
# 1 = card, else invoice. Card requires manual update.
|
|
self['c_PaymentType'] = '1' if payment_method is 'card' else '0'
|
|
|
|
# Unique ID added to 'kpw' when invoicing is allowed.
|
|
self['c_webUserName'] = web_user_name
|
|
|
|
self['c_LevSattKod'] = 2 # 2 = Schenker, 4 = Collect
|
|
self['c_orderStatus'] = None # Override orderStatusCode when using invoicing
|
|
|
|
self['c_ForetagKod'] = 1 # Hardcoded to LK
|
|
self['c_orderStatus'] = None
|
|
self['c_ProvinceCode'] = None # For US customers etc.
|
|
|
|
def callproc(self):
|
|
try:
|
|
return super(PlaceOrder, self).callproc()
|
|
except pymssql.DatabaseError:
|
|
logger.error("A DatabaseException has been caught. Order %d not updated." %
|
|
(self['c_OrderNumber']))
|
|
|
|
|
|
class NotifyInfo(StoredProcedure):
|
|
"""Mapping for the JAPP_spr_LogTrade_Get_NotifyInfo stored procedure parameters
|
|
webapp031 and WEBAPP003 determines default order status"""
|
|
|
|
def __init__(self, company_no):
|
|
super(NotifyInfo, self).__init__('JAPP_spr_LogTrade_Get_NotifyInfo')
|
|
|
|
self['c_FtgNr'] = str(company_no)
|
|
|
|
self['c_ForetagKod'] = 1 # Hardcoded to LK
|
|
|
|
def callproc(self):
|
|
ret = {'email': None, 'sms': None, 'phone': None}
|
|
|
|
try:
|
|
result = super(NotifyInfo, self).callproc(resultset=True)
|
|
except pymssql.DatabaseError:
|
|
logger.error("A DatabaseException has been caught. NotifyInfo not fetched.")
|
|
return ret
|
|
|
|
if isinstance(result, list):
|
|
for r in result:
|
|
if r[1][7:].lower() in ret:
|
|
ret[r[1][7:].lower()] = r[0]
|
|
|
|
return ret
|