# -*- coding: utf-8 -*- """ pyjeeves.models ~~~~~~~~~~~~~~~~~~~~~~ Jeeves raw data models """ from sqlalchemy.schema import ForeignKey, Column from sqlalchemy.orm import relationship from sqlalchemy.types import Integer, String from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.sql.expression import and_ from pyjeeves import logging from .abc import RawBaseModel from .sp_classes import OrderHead, OrderRow, PlaceOrder import re logger = logging.getLogger("PyJeeves." + __name__) class ProductClass(RawBaseModel): __tablename__ = 'xp' __column_map__ = {'ArtProdKlass': 'ProductClassNumber', 'ArtProdklBeskr': 'ProductClassName'} __to_dict_only__ = ('ArtProdKlass', 'ArtProdklBeskr') # print_filter = ('Articles', 'articles_collection') class ArticleClass(RawBaseModel): __tablename__ = 'xm' __column_map__ = {'ArtKod': 'ArticleClassNumber', 'ArtTypBeskr': 'ArticleClassName'} __to_dict_only__ = ('ArtKod', 'ArtTypBeskr') # print_filter = ('Articles', 'articles_collection') class CommodityGroup(RawBaseModel): __tablename__ = 'vg' __column_map__ = {'VaruGruppKod': 'CommodityGroupNumber', 'VaruGruppBeskr': 'CommodityGroupName'} __to_dict_only__ = ('VaruGruppKod', 'VaruGruppBeskr', 'ArticleClass') print_filter = ('Articles', 'articles_collection') # to_json_filter = ('Articles', 'articles_collection') ArtKod = Column(Integer, ForeignKey('xm.ArtKod'), primary_key=True) ArticleClass = relationship(ArticleClass) class ArticleAlternativeUnit(RawBaseModel): __tablename__ = 'xae' __column_map__ = {'AltEnhetKod': 'UnitCode', 'AltEnhetBeskr': 'UnitName', 'AltEnhetOmrFaktor': 'DefaultUnitConv'} __to_dict_only__ = ('AltEnhetBeskr', 'AltEnhetOmrFaktor') class ArticleUnit(RawBaseModel): __tablename__ = 'xare' __column_map__ = {'ArtNr': 'ArticleNumber', 'AltEnhetKod': 'UnitCode', 'AltEnhetOmrFaktor': 'UnitConv', 'AltEnhetOrderStd': 'DefaultSalesUnit'} __to_dict_only__ = ('AltEnhetKod', 'AltEnhetOmrFaktor', 'AltEnhetOrderStd', 'ArticleAlternativeUnit') ArtNr = Column(String, ForeignKey('ar.ArtNr'), primary_key=True) AltEnhetKod = Column(Integer, ForeignKey('xae.AltEnhetKod'), primary_key=True) ArticleAlternativeUnit = relationship(ArticleAlternativeUnit) class ArticleBalance(RawBaseModel): __tablename__ = 'ars' __column_map__ = {'LagSaldo': 'Balance', 'LagResAnt': 'ReservedBalance', 'LagsaldoAltEnh': 'BalanceAlternative', 'LagResAntAltEnh': 'ReservedAlternativeBalance', 'LagStalle': 'StorageLocationNumber'} __to_dict_only__ = ('LagSaldo', 'LagResAnt', 'LagsaldoAltEnh', 'LagResAntAltEnh', 'LagStalle') # print_filter = ('Article', 'articles_collection') # to_json_filter = ('Article', 'articles_collection') ArtNr = Column(Integer, ForeignKey('ar.ArtNr'), primary_key=True) class Article(RawBaseModel): __tablename__ = 'ar' __column_map__ = {'ArtNr': 'ArticleNumber', 'ArtBeskr': 'ArticleName', 'ArtBeskrSpec': 'ArticleSpec', 'Edit': 'ArticleLongSpec', 'LagSaldoArtikel': 'UnitBalance', 'EnhetsKod': 'Unit', 'ArtListPris': 'UnitListPrice', 'Extra1': 'WholeSaleUnit'} __to_dict_only__ = ( 'ArtNr', 'ArtBeskr', 'ArtBeskrSpec', 'Edit', 'CommodityGroup', 'ProductClass', 'ArticleClass', 'ArticleBalance', 'EnhetsKod', 'LagSaldoArtikel', 'RowCreatedDt', 'ArtListPris', 'PictureFileName', 'UnitListPrice', 'Extra1', 'ListPrice', 'Balance') ArtNr = Column(Integer, primary_key=True) VaruGruppKod = Column(Integer, ForeignKey('vg.VaruGruppKod'), primary_key=True) ArtProdKlass = Column(Integer, ForeignKey('xp.ArtProdKlass'), primary_key=True) ArtKod = Column(Integer, ForeignKey('xm.ArtKod'), primary_key=True) CommodityGroup = relationship(CommodityGroup, lazy='joined') ProductClass = relationship(ProductClass, lazy='joined') ArticleClass = relationship(ArticleClass, lazy='joined') ArticleBalance = relationship(ArticleBalance) ArticleUnit = relationship(ArticleUnit) def get_unit_conv(self): if self.ArtFsgForp: return self.ArtFsgForp for unit in self.ArticleUnit: if unit.AltEnhetOrderStd == "1": if unit.AltEnhetOmrFaktor: return unit.AltEnhetOmrFaktor else: return unit.ArticleAlternativeUnit.AltEnhetOmrFaktor return 1 @hybrid_property def ListPrice(self): try: return self.ArtListPris * self.get_unit_conv() except TypeError: logger.debug("NoneType error, %s" % self.ArtNr) @hybrid_property def Balance(self): try: return self.LagSaldoArtikel / self.get_unit_conv() except TypeError: logger.debug("NoneType error, %s" % self.ArtNr) @classmethod def _base_filters(self, obj): return RawBaseModel._base_filters( obj, and_(obj.LagTyp == 0) ) class Company(RawBaseModel): __tablename__ = 'fr' __column_map__ = {'FtgNr': 'CompanyNumber', 'FtgNamn': 'CompanyName'} __to_dict_only__ = ('FtgNr', 'FtgNamn', 'Customer') FtgNr = Column(String, primary_key=True) Customer = relationship('Customer', uselist=False, back_populates='Company', lazy='joined') class DelivLoc(RawBaseModel): __tablename__ = 'lp' class CustomerCategory(RawBaseModel): __tablename__ = 'x1k' KundKategoriKod = Column(Integer, primary_key=True) class Customer(RawBaseModel): __tablename__ = 'kus' __column_map__ = {'FtgNr': 'CompanyNumber', 'kundkategorikod': 'CustomerCategoryCode', 'PrisListaKundSpec': 'PriceListPrimary', 'PrisLista': 'PriceListSecondary'} __to_dict_only__ = ('kundkategorikod', 'PriceList', 'PriceListCommon', 'CustomerCategory', 'PrisLista', 'PrisListaKundSpec') FtgNr = Column(String, ForeignKey('fr.FtgNr'), primary_key=True) KundKategoriKod = Column(Integer, ForeignKey('x1k.KundKategoriKod')) PrisLista = Column(Integer, ForeignKey('prh.PrisLista')) PrisListaKundSpec = Column(Integer, ForeignKey('prh.PrisLista')) Company = relationship("Company", back_populates="Customer") PriceList = relationship("PriceList", uselist=False, lazy='joined', foreign_keys='PriceList.FtgNr') PriceListCommon = relationship("PriceList", uselist=False, foreign_keys='PriceList.PrisLista', primaryjoin="Customer.PrisLista==PriceList.PrisLista") KundKategori = relationship("CustomerCategory") @hybrid_property def CustomerCategory(self): return self.KundKategori.KundKatBeskr if self.KundKategori else "" class PriceList(RawBaseModel): __tablename__ = 'prh' __column_map__ = {'PrisListaBeskr': 'Description', 'PrisLista': 'PriceListNumber', 'MarkUpBelopp': 'PriceFactor'} __to_dict_only__ = ('PrisListaBeskr', 'PrisLista', 'PriceListItems', 'MarkUpBelopp') PrisLista = Column(Integer, primary_key=True) FtgNr = Column(String, ForeignKey('kus.FtgNr')) Customer = relationship('Customer', uselist=False, foreign_keys='Customer.PrisListaKundSpec') PriceListItems = relationship('PriceListItem', back_populates="PriceList", lazy='joined') class PriceListItem(RawBaseModel): __tablename__ = 'prl' __column_map__ = {'ArtNr': 'ArticleNumber', 'vb_pris': 'UnitPrice', 'MarkUpBelopp': 'UnitPriceFactor', 'NollFaktor': 'NullPriceAllowed'} __to_dict_only__ = ('ArtNr', 'vb_pris', 'MarkUpBelopp', 'NollFaktor', 'Price') __to_dict_filter__ = ['PriceList'] # Do not serialize price list relationship __dict_args__ = { 'adapters': { **{ PriceList: None }, **RawBaseModel.__dict_args__['adapters'] } } PrisLista = Column(Integer, ForeignKey('prh.PrisLista'), primary_key=True) ArtNr = Column(Integer, ForeignKey('ar.ArtNr'), primary_key=True) PriceList = relationship('PriceList', uselist=False) Article = relationship(Article) # TODO: Could likely be optimized by getting all articles in one query and mangled in repo @hybrid_property def Price(self): if not self.vb_pris and not self.MarkUpBelopp: return ( (self.Article.ArtListPris + self.PriceList.MarkUpBelopp) * self.Article.get_unit_conv()) if self.vb_pris: return self.vb_pris * self.Article.get_unit_conv() else: return ( (self.Article.ArtListPris + self.MarkUpBelopp) * self.Article.get_unit_conv()) class Order(RawBaseModel): __tablename__ = 'oh' __column_map__ = {'OrderNr': 'OrderNumber', 'FtgNr': 'CompanyNumber', 'OrdDatum': 'OrderDate', 'OrdStat': 'OrderStatusCode', 'OrdLevAdr1': 'AddrName', 'OrdLevAdr2': 'AddrCO', 'OrdLevAdr3': 'AddrStreet', 'OrdLevAdrLandsKod': 'AddrCountry', 'KundBestNr': 'CustomerContact', 'KundRef2': 'CustomerReference', 'GodsMarke1': 'ShippingInfo', 'GodsMarke2': 'InternalInfo', 'TA_MailNotified': 'ShippingEmail', 'TA_PhonNotifiedNo': 'ShippingPhone', 'TA_SMSNotifiedNo': 'ShippingSMS', 'LevSattKod': 'ShippingTypeCode'} __to_dict_only__ = ('OrderNr', 'FtgNr', 'OrdDatum', 'OrdStat', 'CompanyName', 'LevSattKod', 'OrdLevAdr1', 'OrdLevAdr2', 'OrdLevAdr3', 'OrdLevAdrLandsKod', 'KundBestNr', 'KundRef2', 'GodsMarke1', 'GodsMarke2', 'OrderItems', 'AddrPostalCode', 'AddrCity', 'TA_MailNotified', 'TA_PhonNotifiedNo', 'TA_SMSNotifiedNo') __dict_args__ = { 'adapters': { **{ 'OrdDatum': lambda ord_date, *_: ord_date.strftime("%Y-%m-%d"), }, **RawBaseModel.__dict_args__['adapters'] } } OrderNr = Column(Integer, primary_key=True) FtgNr = Column(String, ForeignKey('fr.FtgNr')) Company = relationship('Company', uselist=False) OrderItems = relationship('OrderItem', uselist=True, back_populates="Order", lazy='joined') @hybrid_property def CompanyName(self): return self.Company.FtgNamn if self.Company else "" @CompanyName.setter def CompanyName(self, value): return @hybrid_property def AddrPostalCode(self): if not self.OrdLevAdr4: return s = re.split('(?!\d)\s(?!\d)', self.OrdLevAdr4) return s[0] if len(s) > 1 else '' @AddrPostalCode.setter def AddrPostalCode(self, value): self.OrdLevAdr4 = value + (self.OrdLevAdr4 if self.OrdLevAdr4 else '') @hybrid_property def AddrCity(self): if not self.OrdLevAdr4: return s = re.split('(?!\d)\s(?!\d)', self.OrdLevAdr4, maxsplit=1) return s[1] if len(s) > 1 else '' @AddrCity.setter def AddrCity(self, value): self.OrdLevAdr4 = (self.OrdLevAdr4 if self.OrdLevAdr4 else '') + ' ' + value def create(self, webusername=None): # TODO: Extend with additional functionlity if desired. self['OrderNr'], invoicing_possible = OrderHead(self['FtgNr'], webusername).callproc() return self, invoicing_possible def save(self, invoiced=False): payment_method = 'invoice' if not invoiced: payment_method = 'card' PlaceOrder( self['FtgNr'], self['OrderNr'], payment_method, data=self.to_dict()).callproc() return self class OrderItem(RawBaseModel): __tablename__ = 'orp' __column_map__ = {'OrdRadNr': 'OrderRowNumber', 'vb_pris': 'UnitPrice', 'ArtNr': 'ArticleNumber', 'OrdAntal': 'UnitAmount', 'OrdAntalAltEnh': 'AltUnitAmount', 'AltEnhetKod': 'AltUnit'} __to_dict_only__ = ('OrdRadNr', 'vb_pris', 'ArtNr', 'ArticleName', 'OrdAntal', 'OrdAntalAltEnh', 'AltEnhetKod') # Do not serialize order relationship __dict_args__ = { 'adapters': { **{ Order: None, }, **RawBaseModel.__dict_args__['adapters'] } } OrderNr = Column(Integer, ForeignKey('oh.OrderNr'), primary_key=True) OrdRadNr = Column(Integer, primary_key=True) OrdRadNrStrPos = Column(Integer, primary_key=True) OrdRestNr = Column(Integer, primary_key=True) ArtNr = Column(Integer, ForeignKey('ar.ArtNr')) Order = relationship('Order', uselist=False) Article = relationship(Article) @hybrid_property def ArticleName(self): return self.Article.ArtBeskr if self.Article else "" @ArticleName.setter def ArticleName(self, value): return def save(self): # TODO: Additional information may be returned if desired. row_no = OrderRow( company_no=self['FtgNr'], order_no=self['OrderNr'], item_no=self['ArtNr'], qty=self['OrdAntal'], qty_alt_unit=self['OrdAntalAltEnh'], alt_unit=self['AltEnhetKod'], pers_sign='marlin').callproc() self['OrdRadNr'] = row_no return self