Deps updates, handle more tables + LK code
This commit is contained in:
parent
f649b5f953
commit
5fe140714e
14 changed files with 583 additions and 79 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
|
*.csv
|
||||||
|
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
|
||||||
# C extensions
|
# C extensions
|
||||||
|
|
|
||||||
22
README.md
Normal file
22
README.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# PyJeeves Module
|
||||||
|
|
||||||
|
This project is a Jeeves data extraction and integration project.
|
||||||
|
|
||||||
|
## Initial creation of database schema.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --link db --network marcus_default -v /srv/pyjeeves/config.yml:/app/config.yml gitlab.lndvll.se:5500/lindvallskaffe/pyjeeves python ./pyjeeves/db_raw.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Connecting to DB with client
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -it --network marcus_default --link db:mysql --rm mysql sh -c 'exec mysql -h"db" -P"3306" -uroot -p"ROOT_PW"'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Forcing updates
|
||||||
|
|
||||||
|
You may force updates of objects by setting RowUpdatedDt to null.
|
||||||
|
For example:
|
||||||
|
´update jvs_customers set RowUpdatedDt = null;´
|
||||||
|
|
||||||
22
README.rst
22
README.rst
|
|
@ -1,22 +0,0 @@
|
||||||
PyJeeves Module
|
|
||||||
===============
|
|
||||||
|
|
||||||
This project is a Jeeves data extraction and integration project.
|
|
||||||
|
|
||||||
|
|
||||||
## Initial creation of database schema.
|
|
||||||
|
|
||||||
´docker run --link db --network marcus_default -v /srv/pyjeeves/config.yml:/app/config.yml gitlab.lndvll.se:5500/lindvallskaffe/pyjeeves python ./pyjeeves/db_raw.py´
|
|
||||||
|
|
||||||
|
|
||||||
## Connecting to DB with client
|
|
||||||
|
|
||||||
´docker run -it --network marcus_default --link db:mysql --rm mysql sh -c 'exec mysql -h"db" -P"3306" -uroot -p"ROOT_PW"'´
|
|
||||||
|
|
||||||
|
|
||||||
## Forcing updates
|
|
||||||
|
|
||||||
You may force updates of objects by setting RowUpdatedDt to null.
|
|
||||||
For example:
|
|
||||||
´update jvs_customers set RowUpdatedDt = null;´
|
|
||||||
|
|
||||||
|
|
@ -101,6 +101,7 @@ declare @dbc int,
|
||||||
@jvss_OrderReservation char(1),
|
@jvss_OrderReservation char(1),
|
||||||
@kpwid integer,
|
@kpwid integer,
|
||||||
@OrdBerLevDat DateTime,
|
@OrdBerLevDat DateTime,
|
||||||
|
@OrdBerednDat DateTime,
|
||||||
@SALES007 smallint,
|
@SALES007 smallint,
|
||||||
@kus_AddArtEjAktiv char(1),
|
@kus_AddArtEjAktiv char(1),
|
||||||
@OrdLevAdr4 Jeeves_StrVarChar64
|
@OrdLevAdr4 Jeeves_StrVarChar64
|
||||||
|
|
@ -196,7 +197,8 @@ execute @wi = Jeeves_oh_ordervarde
|
||||||
@c_Foretagkod = @c_ForetagKod
|
@c_Foretagkod = @c_ForetagKod
|
||||||
|
|
||||||
--The estimated delivery date of the order will be set to the earliest delivery date of a row.
|
--The estimated delivery date of the order will be set to the earliest delivery date of a row.
|
||||||
select @OrdBerLevDat = min(OrdBerLevDat) from orp where foretagkod = @c_ForetagKod AND OrderNr = @c_OrderNumber
|
-- Also fetch OrdBerednDat to set base later
|
||||||
|
select @OrdBerLevDat = min(OrdBerLevDat), @OrdBerednDat = min(OrdBerednDat) from orp where foretagkod = @c_ForetagKod AND OrderNr = @c_OrderNumber
|
||||||
|
|
||||||
begin tran
|
begin tran
|
||||||
|
|
||||||
|
|
@ -304,6 +306,8 @@ if @c_PaymentType <> '1' begin
|
||||||
oh.levforetolv = @c_levforetolv,
|
oh.levforetolv = @c_levforetolv,
|
||||||
oh.levsattkod = @Levsattkod,
|
oh.levsattkod = @Levsattkod,
|
||||||
oh.ordberlevdat = @OrdBerLevDat,
|
oh.ordberlevdat = @OrdBerLevDat,
|
||||||
|
oh.ohordberlevdatbase = @OrdBerLevDat, -- Fix base LevDat and BerednDat. Used when adding rows in GUI.
|
||||||
|
oh.ohordberedndatbase = @OrdBerednDat,
|
||||||
oh.ordlevadr1 = @c_CoName,
|
oh.ordlevadr1 = @c_CoName,
|
||||||
oh.ordlevadr2 = @c_Addr1,
|
oh.ordlevadr2 = @c_Addr1,
|
||||||
oh.ordlevadr3 = @c_Addr2,
|
oh.ordlevadr3 = @c_Addr2,
|
||||||
|
|
@ -356,6 +360,8 @@ end else begin
|
||||||
oh.levforetolv = @c_levforetolv,
|
oh.levforetolv = @c_levforetolv,
|
||||||
oh.levsattkod = @Levsattkod,
|
oh.levsattkod = @Levsattkod,
|
||||||
oh.ordberlevdat = @OrdBerLevDat,
|
oh.ordberlevdat = @OrdBerLevDat,
|
||||||
|
oh.ohordberlevdatbase = @OrdBerLevDat, -- Fix base LevDat and BerednDat. Used when adding rows in GUI.
|
||||||
|
oh.ohordberedndatbase = @OrdBerednDat,
|
||||||
oh.ordlevadr1 = @c_CoName,
|
oh.ordlevadr1 = @c_CoName,
|
||||||
oh.ordlevadr2 = @c_Addr1,
|
oh.ordlevadr2 = @c_Addr1,
|
||||||
oh.ordlevadr3 = @c_Addr2,
|
oh.ordlevadr3 = @c_Addr2,
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,9 @@ class DBConnector(object):
|
||||||
def __init__(self, enabled_clients=['raw'], metadata=None):
|
def __init__(self, enabled_clients=['raw'], metadata=None):
|
||||||
logger.info("Creating engines and sessionmakers")
|
logger.info("Creating engines and sessionmakers")
|
||||||
|
|
||||||
self.raw, self.raw_engine = (self.raw_session() if 'raw' in enabled_clients else {})
|
self.enabled_clients = enabled_clients
|
||||||
|
self.raw_db, self.raw_session, self.raw_engine = (
|
||||||
|
self.raw_client() if 'raw' in enabled_clients else {})
|
||||||
self.meta = (self.meta_session() if 'meta' in enabled_clients else {})
|
self.meta = (self.meta_session() if 'meta' in enabled_clients else {})
|
||||||
|
|
||||||
def callproc(self, procedure="", params=[]):
|
def callproc(self, procedure="", params=[]):
|
||||||
|
|
@ -90,14 +92,22 @@ class DBConnector(object):
|
||||||
conn.close()
|
conn.close()
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def raw_session(self):
|
def raw_client(self):
|
||||||
|
if 'raw' not in self.enabled_clients:
|
||||||
|
logger.error('Raw client is not enabled')
|
||||||
|
|
||||||
|
logger.info("Using DB %s" % config.config['databases']['raw']['db'])
|
||||||
|
|
||||||
uri = 'mssql+pymssql://{user}:{pw}@{host}:{port}/{db}?charset=utf8'.format(
|
uri = 'mssql+pymssql://{user}:{pw}@{host}:{port}/{db}?charset=utf8'.format(
|
||||||
**config.config['databases']['raw'])
|
**config.config['databases']['raw'])
|
||||||
sql_client_config = {'SQL_DATABASE_URI': uri}
|
sql_client_config = {'SQL_DATABASE_URI': uri}
|
||||||
db = SQLClient(sql_client_config, query_class=BaseFilterQuery)
|
db = SQLClient(sql_client_config, query_class=BaseFilterQuery)
|
||||||
|
|
||||||
return db.session, db.engine
|
return db, db.session, db.engine
|
||||||
|
|
||||||
|
def set_model_class(self, model_class):
|
||||||
|
self.raw_db.model_class = model_class
|
||||||
|
self.raw_db.update_models_registry()
|
||||||
|
|
||||||
def meta_session(self):
|
def meta_session(self):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,11 @@ logger.info("Reading Jeeves DB structure")
|
||||||
|
|
||||||
meta = MetaData()
|
meta = MetaData()
|
||||||
try:
|
try:
|
||||||
meta.reflect(bind=db.raw.connection(),
|
meta.reflect(bind=db.raw_session.connection(),
|
||||||
only=['ar', 'ars', 'xae', 'xare', 'fr', 'kus', 'x1k',
|
only=['ar', 'ars', 'arsh', 'arean', 'xae', 'xare', 'fr', 'kus', 'x1k',
|
||||||
'oh', 'orp', 'lp', 'vg', 'xp', 'xm', 'prh', 'prl',
|
'oh', 'orp', 'lp', 'vg', 'xp', 'xm', 'prh', 'prl',
|
||||||
'kp', 'kpw', 'cr', 'X4', 'xw', 'X1'])
|
'kp', 'kpw', 'cr', 'X4', 'xw', 'X1',
|
||||||
|
'JAPP_EWMS_Item_Replenishment_Levels'])
|
||||||
except OperationalError as e:
|
except OperationalError as e:
|
||||||
logger.error("Failed to read Jeeves DB structure")
|
logger.error("Failed to read Jeeves DB structure")
|
||||||
raise e
|
raise e
|
||||||
|
|
@ -194,3 +195,6 @@ def receive_attribute_instrument(cls, key, inst):
|
||||||
"listen for the 'attribute_instrument' event"
|
"listen for the 'attribute_instrument' event"
|
||||||
|
|
||||||
install_validator_listner(cls, key, inst)
|
install_validator_listner(cls, key, inst)
|
||||||
|
|
||||||
|
|
||||||
|
db.set_model_class(RawBaseModel)
|
||||||
|
|
|
||||||
|
|
@ -52,3 +52,5 @@ class LengthValidator():
|
||||||
state.__class__.__name__, state.__class__._map_columns(self.col_name),
|
state.__class__.__name__, state.__class__._map_columns(self.col_name),
|
||||||
len(value), self.max_length))
|
len(value), self.max_length))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
# Add more validators, such as type for ints.
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,8 @@ class ArticleUnit(RawBaseModel):
|
||||||
|
|
||||||
ArtNr = Column(String, ForeignKey('ar.ArtNr'), primary_key=True)
|
ArtNr = Column(String, ForeignKey('ar.ArtNr'), primary_key=True)
|
||||||
|
|
||||||
AltEnhetKod = Column(Integer, ForeignKey('xae.AltEnhetKod'), primary_key=True)
|
AltEnhetKod = Column(String, ForeignKey('xae.AltEnhetKod'), primary_key=True)
|
||||||
ArticleAlternativeUnit = relationship(ArticleAlternativeUnit)
|
ArticleAlternativeUnit = relationship(ArticleAlternativeUnit, lazy='joined')
|
||||||
|
|
||||||
|
|
||||||
class ArticleBalance(RawBaseModel):
|
class ArticleBalance(RawBaseModel):
|
||||||
|
|
@ -89,6 +89,30 @@ class ArticleBalance(RawBaseModel):
|
||||||
ArtNr = Column(Integer, ForeignKey('ar.ArtNr'), primary_key=True)
|
ArtNr = Column(Integer, ForeignKey('ar.ArtNr'), primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ArticleEAN(RawBaseModel):
|
||||||
|
__tablename__ = 'arean'
|
||||||
|
__column_map__ = {'ArtNrEAN': 'EAN', 'ArtNr': 'ArticleNumber'}
|
||||||
|
__to_dict_only__ = ('ArtNr', 'ArtNrEAN', 'ArticleUnit')
|
||||||
|
|
||||||
|
ArtNr = Column(String, ForeignKey('ar.ArtNr'), primary_key=True)
|
||||||
|
ArtNrEAN = Column(String, primary_key=True)
|
||||||
|
AltEnhetKod = Column(String, ForeignKey('xare.AltEnhetKod'))
|
||||||
|
|
||||||
|
ArticleUnit = relationship(ArticleUnit, lazy='joined')
|
||||||
|
|
||||||
|
|
||||||
|
class ArticleShelf(RawBaseModel):
|
||||||
|
__tablename__ = 'arsh'
|
||||||
|
__column_map__ = {'LagPlats': 'Shelf',
|
||||||
|
'LagStalle': 'WarehouseID',
|
||||||
|
'JAPP_EWMS_zoneid': 'WMSZoneID',
|
||||||
|
'ArtNr': 'ArticleNumber'}
|
||||||
|
__to_dict_only__ = ('LagPlats', 'LagStalle', 'JAPP_EWMS_zoneid', 'ArtNr')
|
||||||
|
|
||||||
|
LagPlats = Column(String, ForeignKey('ar.ArtNr'), primary_key=True)
|
||||||
|
LagStalle = Column(String, ForeignKey('ar.ArtNr'), primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
class VATRate(RawBaseModel):
|
class VATRate(RawBaseModel):
|
||||||
__tablename__ = 'X1'
|
__tablename__ = 'X1'
|
||||||
__column_map__ = {'MomsKod': 'VATID', 'MomsSats': 'VATRate'}
|
__column_map__ = {'MomsKod': 'VATID', 'MomsSats': 'VATRate'}
|
||||||
|
|
@ -200,12 +224,12 @@ class Article(RawBaseModel):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
logger.debug("NoneType error, %s" % self.ArtNr)
|
logger.debug("NoneType error, %s" % self.ArtNr)
|
||||||
|
|
||||||
@classmethod
|
# @classmethod
|
||||||
def _base_filters(self, obj):
|
# def _base_filters(self, obj):
|
||||||
return RawBaseModel._base_filters(
|
# return RawBaseModel._base_filters(
|
||||||
obj,
|
# obj,
|
||||||
and_(obj.ItemStatusCode == 0)
|
# and_(obj.ItemStatusCode == 0)
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
|
||||||
class ContactInformationType(RawBaseModel):
|
class ContactInformationType(RawBaseModel):
|
||||||
|
|
@ -535,3 +559,16 @@ class OrderItem(RawBaseModel):
|
||||||
pers_sign=self['PersSign']).callproc()
|
pers_sign=self['PersSign']).callproc()
|
||||||
self['OrdRadNr'] = row_no
|
self['OrdRadNr'] = row_no
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class ItemReplenishmentLevels(RawBaseModel):
|
||||||
|
# __table_args__ = {'mssql_autoincrement': False, 'extend_existing': True}
|
||||||
|
# __table_args__ = {'implicit_returning': False, 'extend_existing': True}
|
||||||
|
__tablename__ = 'JAPP_EWMS_Item_Replenishment_Levels'
|
||||||
|
__column_map__ = {'ArtNr': 'ArticleNumber', 'LagPlats': 'Shelf', 'LagStalle': 'WarehouseID'}
|
||||||
|
__to_dict_only__ = ('LagPlats', 'ArtNr')
|
||||||
|
|
||||||
|
# Workaround for:
|
||||||
|
# "Table 'JAPP_EWMS_Item_Replenishment_Levels' does not have the identity property.
|
||||||
|
# Cannot perform SET operation."
|
||||||
|
ForetagKod = Column(Integer, primary_key=True, autoincrement=False)
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,11 @@ class StoredProcedure(OrderedDict):
|
||||||
FROM sys.objects AS SO
|
FROM sys.objects AS SO
|
||||||
INNER JOIN sys.parameters AS P
|
INNER JOIN sys.parameters AS P
|
||||||
ON SO.OBJECT_ID = P.OBJECT_ID
|
ON SO.OBJECT_ID = P.OBJECT_ID
|
||||||
WHERE SO.name LIKE '%Jeeves_Esales_%' OR
|
WHERE (
|
||||||
SO.name LIKE '%JAPP_spr_LogTrade_%' AND
|
SO.name LIKE '%Jeeves_Esales_%' OR
|
||||||
SO.OBJECT_ID IN ( SELECT OBJECT_ID
|
SO.name LIKE '%JAPP_spr_LogTrade_%'
|
||||||
|
) AND
|
||||||
|
SO.OBJECT_ID IN ( SELECT OBJECT_ID
|
||||||
FROM sys.objects
|
FROM sys.objects
|
||||||
WHERE TYPE IN ('P','FN'))
|
WHERE TYPE IN ('P','FN'))
|
||||||
ORDER BY [Schema], SO.name, P.parameter_id"""
|
ORDER BY [Schema], SO.name, P.parameter_id"""
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,5 @@ from .location import Location
|
||||||
from .article import Article, ArticleCategory
|
from .article import Article, ArticleCategory
|
||||||
from .company import Company
|
from .company import Company
|
||||||
from .pricelist import PriceList
|
from .pricelist import PriceList
|
||||||
from .order import Order
|
from .order import Order
|
||||||
|
from .warehouse import Warehouse
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from pyjeeves.models.raw import Article as ArticleModel, ProductClass, ArticleClass, CommodityGroup
|
from pyjeeves.models.raw import (
|
||||||
|
Article as ArticleModel,
|
||||||
|
ProductClass, ArticleClass, CommodityGroup, ArticleEAN, ArticleUnit)
|
||||||
from pyjeeves.models import db
|
from pyjeeves.models import db
|
||||||
from sqlalchemy.sql.expression import and_
|
from sqlalchemy.sql.expression import and_
|
||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
|
from gtin import GTIN
|
||||||
|
|
||||||
from pyjeeves import logging
|
from pyjeeves import logging
|
||||||
logger = logging.getLogger("PyJeeves." + __name__)
|
logger = logging.getLogger("PyJeeves." + __name__)
|
||||||
|
|
@ -17,22 +20,31 @@ class Article():
|
||||||
def get(art_no):
|
def get(art_no):
|
||||||
""" Query an article by number """
|
""" Query an article by number """
|
||||||
try:
|
try:
|
||||||
return db.raw.query(ArticleModel).filter_by(
|
return db.raw_session.query(ArticleModel).filter_by(
|
||||||
ArtNr=str(art_no)
|
ArtNr=str(art_no)
|
||||||
).one()
|
).one()
|
||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all(filter_=and_(ArticleModel.ItemStatusCode == 0, ArticleModel.ArtKod != 2)):
|
def get_all(filter_=and_(
|
||||||
|
ArticleModel.ItemStatusCode == 0,
|
||||||
|
ArticleModel.ArtKod != 2,
|
||||||
|
ArticleModel.VaruGruppKod != 90,
|
||||||
|
ArticleModel.ArtProdKlass != 0)
|
||||||
|
):
|
||||||
# .filter_by(ItemStatusCode=0, ArtKod=2)
|
# .filter_by(ItemStatusCode=0, ArtKod=2)
|
||||||
return db.raw.query(ArticleModel).filter(filter_).all()
|
return db.raw_session.query(ArticleModel).filter(filter_).all()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_article_units(filter_=and_()):
|
||||||
|
return db.raw_session.query(ArticleUnit).filter(filter_).all()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_salable(art_no_list=[]):
|
def is_salable(art_no_list=[]):
|
||||||
""" Returns true if all articles are salable,
|
""" Returns true if all articles are salable,
|
||||||
else false with error information """
|
else false with error information """
|
||||||
articles = db.raw.query(ArticleModel).filter(
|
articles = db.raw_session.query(ArticleModel).filter(
|
||||||
and_(ArticleModel.ArtNr.in_(art_no_list))).all()
|
and_(ArticleModel.ArtNr.in_(art_no_list))).all()
|
||||||
|
|
||||||
blocked_articles = [article.ArtNr for article in articles
|
blocked_articles = [article.ArtNr for article in articles
|
||||||
|
|
@ -50,6 +62,43 @@ class Article():
|
||||||
|
|
||||||
return True, {}
|
return True, {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_article_gtins():
|
||||||
|
return db.raw_session.query(ArticleEAN).all()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_article_gtins(gtins=[], dry_run=False):
|
||||||
|
# Expects a list of dicts like this:
|
||||||
|
# [{
|
||||||
|
# 'article_no': article.ArtNr,
|
||||||
|
# 'article_gtin': gtin,
|
||||||
|
# 'unit': unit.AltEnhetKod,
|
||||||
|
# }]
|
||||||
|
for gtin in gtins:
|
||||||
|
n1 = ArticleEAN(
|
||||||
|
ArtNr=gtin['article_no'], AltEnhetKod=gtin.get('unit', None),
|
||||||
|
ArtNrEAN=str(gtin['article_gtin']), ForetagKod=1)
|
||||||
|
if dry_run:
|
||||||
|
logger.info('Creating GTIN for %s, %s, %s' % (n1.ArtNr, n1.AltEnhetKod, n1.ArtNrEAN))
|
||||||
|
continue
|
||||||
|
|
||||||
|
db.raw_db.add(n1)
|
||||||
|
logger.debug('Created/updated Article EAN for %s - %s with GTIN %s' % (
|
||||||
|
gtin['article_no'], gtin.get('unit', 'no unit'), gtin['article_gtin']))
|
||||||
|
|
||||||
|
db.raw_db.commit()
|
||||||
|
logger.info('Succesfully commited %s GTINs to database' % (len(gtins)))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clear_article_gtins():
|
||||||
|
gtins = db.raw_session.query(ArticleEAN).all()
|
||||||
|
|
||||||
|
for gtin in gtins:
|
||||||
|
db.raw_db.delete(gtin)
|
||||||
|
|
||||||
|
db.raw_db.commit()
|
||||||
|
logger.info('Deleted %s GTINs' % (len(gtins)))
|
||||||
|
|
||||||
|
|
||||||
class ArticleCategory():
|
class ArticleCategory():
|
||||||
"""Handles article categories, such as classes and groups in Jeeves"""
|
"""Handles article categories, such as classes and groups in Jeeves"""
|
||||||
|
|
@ -57,27 +106,362 @@ class ArticleCategory():
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all():
|
def get_all():
|
||||||
# .filter_by(ItemStatusCode=0, ArtKod=2)
|
# .filter_by(ItemStatusCode=0, ArtKod=2)
|
||||||
prod_classes = db.raw.query(ProductClass).all()
|
prod_classes = db.raw_session.query(ProductClass).all()
|
||||||
art_classes = db.raw.query(ArticleClass).all()
|
art_classes = db.raw_session.query(ArticleClass).all()
|
||||||
com_groups = db.raw.query(CommodityGroup).all()
|
com_groups = db.raw_session.query(CommodityGroup).all()
|
||||||
|
|
||||||
return {'ProductClasses': prod_classes,
|
return {'ProductClasses': prod_classes,
|
||||||
'ArticleClasses': art_classes, 'CommodityGroups': com_groups}
|
'ArticleClasses': art_classes, 'CommodityGroups': com_groups}
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Should be moved to separate project with Lindvalls specific code
|
||||||
|
def get_gtin_for_article(article_ean, article_unit=None, use_prefix=True):
|
||||||
|
# If we don't want to prefix with 0, then exclude them here.
|
||||||
|
UNIT_MAPPING = {
|
||||||
|
'Påse': '',
|
||||||
|
'st': '',
|
||||||
|
'paket': 0,
|
||||||
|
'200g': 0,
|
||||||
|
'kg': 9,
|
||||||
|
'Kart': 1,
|
||||||
|
'Bricka': 1,
|
||||||
|
'½-pall': 2,
|
||||||
|
'tray_no_wrap': 8
|
||||||
|
}
|
||||||
|
prefixes = []
|
||||||
|
if article_unit:
|
||||||
|
# Find matching values in unit mapping
|
||||||
|
prefixes = [
|
||||||
|
val for key, val in UNIT_MAPPING.items()
|
||||||
|
if article_unit[0:len(key)].lower() in key.lower()]
|
||||||
|
if len(prefixes) > 1:
|
||||||
|
logger.warning('More than one unit match found in unit mapping')
|
||||||
|
|
||||||
|
# Use the first match
|
||||||
|
raw_gtin = (str(prefixes[0]) + article_ean) if prefixes and use_prefix else article_ean
|
||||||
|
|
||||||
|
# Handle GS1-128 GTIN code
|
||||||
|
if len(raw_gtin) >= 15 and raw_gtin[0:2] == '01':
|
||||||
|
raw_gtin = raw_gtin[2::]
|
||||||
|
|
||||||
|
article_gtin = GTIN(raw=raw_gtin)
|
||||||
|
|
||||||
|
return article_gtin
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Should be moved to separate project with Lindvalls specific code
|
||||||
|
def create_gtins_for_trading_goods(filename='gtin_trading_goods.csv'):
|
||||||
|
articles = Article.get_all(and_(
|
||||||
|
ArticleModel.ArtProdKlass == 4))
|
||||||
|
|
||||||
|
gtins = []
|
||||||
|
gtin_data = {}
|
||||||
|
|
||||||
|
import csv
|
||||||
|
with open(filename, newline='') as csvfile:
|
||||||
|
gtinreader = csv.reader(csvfile, delimiter=',')
|
||||||
|
headers = gtinreader.__next__()
|
||||||
|
logger.info('Found these columns: %s' % (', '.join(headers)))
|
||||||
|
|
||||||
|
for row in gtinreader:
|
||||||
|
gtin_data[row[0]] = row
|
||||||
|
|
||||||
|
logger.info("Found %s articles and updating with %s rows of data" % (
|
||||||
|
len(articles), len(gtin_data)))
|
||||||
|
|
||||||
|
for article in articles:
|
||||||
|
data = gtin_data.get(article.ArtNr)
|
||||||
|
if data:
|
||||||
|
default_set = False
|
||||||
|
if len(article.ArticleUnit) == 0 and data[3]:
|
||||||
|
logger.warning('Article %s has no ArticleUnits, but requires it' % (article.ArtNr))
|
||||||
|
|
||||||
|
for unit in article.ArticleUnit:
|
||||||
|
if unit.AltEnhetKod[0:3] == 'kart' and not data[3]:
|
||||||
|
logger.warning('Article %s missing kart unit' % (article.ArtNr))
|
||||||
|
|
||||||
|
if data[3] and unit.AltEnhetKod != 'st':
|
||||||
|
gtin = get_gtin_for_article(data[3], unit.AltEnhetKod, False)
|
||||||
|
# Only add GTINs for order units (not PO units)
|
||||||
|
if unit.AltEnhetOrder == '1':
|
||||||
|
gtins.append({
|
||||||
|
'article_no': article.ArtNr,
|
||||||
|
'article_gtin': gtin,
|
||||||
|
'unit': unit.AltEnhetKod
|
||||||
|
})
|
||||||
|
if unit.AltEnhetKod == 'st':
|
||||||
|
gtin = get_gtin_for_article(data[2], unit.AltEnhetKod, False)
|
||||||
|
# Only add GTINs for order units (not PO units)
|
||||||
|
if unit.AltEnhetOrder == '1':
|
||||||
|
gtins.append({
|
||||||
|
'article_no': article.ArtNr,
|
||||||
|
'article_gtin': gtin,
|
||||||
|
'unit': unit.AltEnhetKod
|
||||||
|
})
|
||||||
|
default_set = True
|
||||||
|
|
||||||
|
# Add default gtin if 'st' not used
|
||||||
|
if not default_set:
|
||||||
|
gtin = get_gtin_for_article(data[2], None, False)
|
||||||
|
gtins.append({
|
||||||
|
'article_no': article.ArtNr,
|
||||||
|
'article_gtin': gtin
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# Warn about active and stock items that didn't get updated.
|
||||||
|
if article.LagTyp == 0 and article.ItemStatusCode == 0:
|
||||||
|
logger.warning('Article %s has no GTIN data in CSV' % (article.ArtNr))
|
||||||
|
|
||||||
|
Article.add_article_gtins(gtins)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Should be moved to separate project with Lindvalls specific code
|
||||||
|
def create_gtins(dry_run=True):
|
||||||
|
# GS1 Company Prefixes that we manage locally, prefixing etc.
|
||||||
|
LOCAL_GCPS = [
|
||||||
|
'731083', # Lindvalls Kaffe
|
||||||
|
'7392736', # Sackeus AB
|
||||||
|
'735007318', # Sarria Import AB
|
||||||
|
'732157', # Martin & Servera AB
|
||||||
|
'350096', # Scænsei Thee Kompani AB (Used by REKYL In Omnia Paratus AB)
|
||||||
|
'735003307', # Coffee Please
|
||||||
|
'735003711', # Emmas Skafferi AB (Used by Coffee Please)
|
||||||
|
'735003712', # Prefix no longer subscribed (Used by Coffee Please)
|
||||||
|
'735003302', # Josephine Selander - YogaGo (Used by Coffee Please)
|
||||||
|
]
|
||||||
|
|
||||||
|
articles = Article.get_all(and_(
|
||||||
|
ArticleModel.ItemStatusCode == 0,
|
||||||
|
ArticleModel.VaruGruppKod != 90,
|
||||||
|
ArticleModel.ArtProdKlass != 0))
|
||||||
|
|
||||||
|
articles_with_existing_gtins = [
|
||||||
|
gtin.ArtNr for i, gtin in enumerate(Article.get_article_gtins())]
|
||||||
|
|
||||||
|
gtins = []
|
||||||
|
|
||||||
|
for article in articles:
|
||||||
|
if article.ArtNr in articles_with_existing_gtins:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not article.ArtStreckKod:
|
||||||
|
logger.warning('No base GTIN for article %s' % (article.ArtNr))
|
||||||
|
continue
|
||||||
|
|
||||||
|
GCP = GTIN(raw=article.ArtStreckKod).gcp
|
||||||
|
|
||||||
|
if 12 < len(article.ArtStreckKod) < 12 and GCP in LOCAL_GCPS:
|
||||||
|
logger.error('Base GTIN is wrong length for article %s' % (article.ArtNr))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# If GTIN is provided by vendor, skip prefixes and gohead if only one or no units exist.
|
||||||
|
if GCP not in LOCAL_GCPS and len(article.ArticleUnit) <= 1:
|
||||||
|
use_prefix = False
|
||||||
|
logger.info('Externally provided GTIN for %s, skipping prefixes' % (article.ArtNr))
|
||||||
|
elif GCP not in LOCAL_GCPS and len(article.ArticleUnit) > 1:
|
||||||
|
logger.warning('Externally provided GTIN for %s, too many units' % (article.ArtNr))
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
use_prefix = True
|
||||||
|
|
||||||
|
# Create gtin without ArticleUnit, for the base unit.
|
||||||
|
# gtins.append({
|
||||||
|
# 'article_no': article.ArtNr,
|
||||||
|
# 'article_gtin': get_gtin_for_article(article.ArtStreckKod, None, False)
|
||||||
|
# })
|
||||||
|
|
||||||
|
for unit in article.ArticleUnit:
|
||||||
|
|
||||||
|
# Skip paket for 21%, should only match HV with plastic wrapping.
|
||||||
|
if article.ArtNr[0:2] == '21' and unit.AltEnhetKod[0:6].lower() == 'paket':
|
||||||
|
logger.info('Skip paket unit for %s' % (article.ArtNr))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Special for 20%/30%, should only match HV without plastic wrapping.
|
||||||
|
if article.ArtNr[0:2] in ('20', '30') and unit.AltEnhetKod[0:6].lower() == 'bricka':
|
||||||
|
unit_code = 'tray_no_wrap'
|
||||||
|
else:
|
||||||
|
unit_code = unit.AltEnhetKod
|
||||||
|
|
||||||
|
gtin = get_gtin_for_article(article.ArtStreckKod, unit_code, use_prefix)
|
||||||
|
|
||||||
|
# Only add GTINs for order units (not PO units)
|
||||||
|
if unit.AltEnhetOrder == '1':
|
||||||
|
gtins.append({
|
||||||
|
'article_no': article.ArtNr,
|
||||||
|
'article_gtin': gtin,
|
||||||
|
'unit': unit.AltEnhetKod
|
||||||
|
})
|
||||||
|
|
||||||
|
# Workaround for scanning HV base units without plastic wrapping
|
||||||
|
if str(gtin)[0] == '0':
|
||||||
|
# Create gtin without ArticleUnit, for the base unit.
|
||||||
|
gtins.append({
|
||||||
|
'article_no': article.ArtNr,
|
||||||
|
'article_gtin': get_gtin_for_article(article.ArtStreckKod, None, False)
|
||||||
|
})
|
||||||
|
|
||||||
|
# Add GTIN to articles that don't use article units
|
||||||
|
# Should this still be added to arean/ArticleEAN???
|
||||||
|
# if len(article.ArticleUnit) == 0:
|
||||||
|
# gtin = get_gtin_for_article(article.ArtStreckKod, None, use_prefix)
|
||||||
|
# gtins.append({
|
||||||
|
# 'article_no': article.ArtNr,
|
||||||
|
# 'article_gtin': gtin,
|
||||||
|
# 'unit': None,
|
||||||
|
# })
|
||||||
|
# add_gtin_for_article(
|
||||||
|
# article.ArtNr, article.ArtStreckKod, None, use_prefix)
|
||||||
|
|
||||||
|
Article.add_article_gtins(gtins, dry_run)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Should be moved to separate project with Lindvalls specific code
|
||||||
|
def find_articles_without_base_gtin():
|
||||||
|
articles = Article.get_all(and_(
|
||||||
|
ArticleModel.ItemStatusCode == 0,
|
||||||
|
ArticleModel.VaruGruppKod != 90,
|
||||||
|
ArticleModel.ArtProdKlass != 0))
|
||||||
|
|
||||||
|
_list = []
|
||||||
|
|
||||||
|
for article in articles:
|
||||||
|
if not article.ArtStreckKod:
|
||||||
|
_list.append(
|
||||||
|
{'artnr': article.ArtNr,
|
||||||
|
'artbeskr': article.ArtBeskr,
|
||||||
|
'error': 'no_base'})
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if 12 < len(article.ArtStreckKod) < 12:
|
||||||
|
_list.append(
|
||||||
|
{'artnr': article.ArtNr,
|
||||||
|
'artbeskr': article.ArtBeskr,
|
||||||
|
'error': 'wrong_length'})
|
||||||
|
continue
|
||||||
|
|
||||||
|
for item in _list:
|
||||||
|
print('{artnr}, "{artbeskr}", {error}'.format(**item))
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Should be moved to separate project with Lindvalls specific code
|
||||||
|
def set_storage_type():
|
||||||
|
articles = Article.get_all(and_(
|
||||||
|
ArticleModel.LagTyp == 0,
|
||||||
|
ArticleModel.ItemStatusCode == 0,
|
||||||
|
ArticleModel.AnskaffningsSatt == 10))
|
||||||
|
|
||||||
|
for article in articles:
|
||||||
|
article.LagTyp = 4
|
||||||
|
|
||||||
|
db.raw_db.commit()
|
||||||
|
|
||||||
|
logger.info("Updated storage type for %s articles" % (len(articles)))
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Should be moved to separate project with Lindvalls specific code
|
||||||
|
def set_zone_placement():
|
||||||
|
# Logic for article groups and zones
|
||||||
|
# ArticleClass descides which zone to put it.
|
||||||
|
# set Article.ArticleBalance[0].japp_ewms_rec_zoneid to correct zoneid
|
||||||
|
|
||||||
|
article_class_map = {
|
||||||
|
'Kaffe': 'U',
|
||||||
|
'OoH-Kaffe': 'K',
|
||||||
|
'Private Label': 'S',
|
||||||
|
'Tillbehör och maskiner': 'U',
|
||||||
|
'Komplement': 'U'
|
||||||
|
}
|
||||||
|
|
||||||
|
articles = Article.get_all(and_(
|
||||||
|
ArticleModel.ItemStatusCode == 0,
|
||||||
|
ArticleModel.AnskaffningsSatt == 10))
|
||||||
|
|
||||||
|
zone_placements_update = 0
|
||||||
|
for article in articles:
|
||||||
|
zone_id = article_class_map.get(article.ArticleClass.ArtTypBeskr)
|
||||||
|
if zone_id and article.ArticleBalance:
|
||||||
|
article.ArticleBalance[0].JAPP_EWMS_REC_ZoneID = zone_id
|
||||||
|
zone_placements_update += 1
|
||||||
|
else:
|
||||||
|
logger.info("Excluded %s, wrong article class or no balance " % (article.ArtNr))
|
||||||
|
|
||||||
|
db.raw_db.commit()
|
||||||
|
|
||||||
|
logger.info("Updated placement zone for %s articles" % (zone_placements_update))
|
||||||
|
|
||||||
|
# a = Article.get('2109')
|
||||||
|
# print([ab.to_dict() for ab in a['ArticleBalance']])
|
||||||
|
|
||||||
|
|
||||||
|
def update_decimals_on_alt_units():
|
||||||
|
units = Article.get_article_units(ArticleUnit.AltEnhetKod == 'påse')
|
||||||
|
|
||||||
|
updated_units = 0
|
||||||
|
|
||||||
|
for unit in units:
|
||||||
|
if unit.AltEnhetOmrFaktor is not None:
|
||||||
|
dec_count = 0
|
||||||
|
for digit in unit.AltEnhetOmrFaktor.as_tuple().digits:
|
||||||
|
if digit != 0:
|
||||||
|
dec_count += 1
|
||||||
|
unit.AltEnhetAntDec = dec_count
|
||||||
|
|
||||||
|
updated_units += 1
|
||||||
|
|
||||||
|
db.raw_db.commit()
|
||||||
|
logger.info("Updated decimal count for %s article units" % (updated_units))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# print([column.key for column in Company.__table__.columns])
|
# print([column.key for column in Company.__table__.columns])
|
||||||
|
|
||||||
logger.info("Starting TEST")
|
# from pprint import pprint
|
||||||
|
# logger.info("Starting TEST")
|
||||||
|
|
||||||
# session = RawSession()
|
# session = RawSession()
|
||||||
|
|
||||||
logger.info("Testing gettings an article")
|
# logger.info("Testing gettings an article")
|
||||||
# c1 = session.query(Company).filter_by(FtgNr="179580").first()
|
# # c1 = session.query(Company).filter_by(FtgNr="179580").first()
|
||||||
# print(ArticleModel)
|
# # print(ArticleModel)
|
||||||
c1 = ArticleModel.query.filter_by(ArtNr="2103").first()
|
# c1 = db.raw_session.query(ArticleModel).filter_by(ArtNr="2003").first()
|
||||||
print(c1)
|
# c1 = Article.get("2003")
|
||||||
logger.info(c1.json)
|
# pprint([unit.to_dict() for unit in c1.ArticleUnit])
|
||||||
|
# pprint(c1.to_dict())
|
||||||
|
# pprint([(au.to_dict(), au.AltEnhetOrder) for au in c1.ArticleUnit])
|
||||||
|
# logger.info(c1.to_dict())
|
||||||
|
|
||||||
print(
|
# print(
|
||||||
len(ArticleModel.get_all())
|
# len(Article.get_all())
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
# c1 = db.raw_session.query(ArticleEAN).all()
|
||||||
|
# pprint([c.to_dict() for c in c1])
|
||||||
|
|
||||||
|
# c1 = db.raw_session.query(ArticleEAN).filter_by(ArtNr="1054").first()
|
||||||
|
# pprint(c1.to_dict())
|
||||||
|
# c1.ArtNrEAN = '7310830010548'
|
||||||
|
# pprint(c1.to_dict())
|
||||||
|
# c1.save()
|
||||||
|
# logger.info(c1.to_dict())
|
||||||
|
# create_gtins_for_trading_goods('gtin_trading_goods_test.csv')
|
||||||
|
|
||||||
|
# LIVE FUNCTIONS BELOW
|
||||||
|
|
||||||
|
# find_articles_without_base_gtin()
|
||||||
|
|
||||||
|
# logger.info("Truncating GTINs")
|
||||||
|
# Article.clear_article_gtins()
|
||||||
|
logger.info("Creating new GTINs from base GTIN")
|
||||||
|
create_gtins(dry_run=False)
|
||||||
|
# logger.info("Creating new GTINs from trading goods CSV")
|
||||||
|
# create_gtins_for_trading_goods()
|
||||||
|
|
||||||
|
# logger.info("Update articles for batch management")
|
||||||
|
# set_storage_type()
|
||||||
|
|
||||||
|
# logger.info("Set zone information on article balance")
|
||||||
|
# set_zone_placement()
|
||||||
|
|
||||||
|
# logger.info("Updating alt units")
|
||||||
|
# update_decimals_on_alt_units()
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class Company():
|
||||||
def get(ftg_nr):
|
def get(ftg_nr):
|
||||||
""" Query an article by number """
|
""" Query an article by number """
|
||||||
try:
|
try:
|
||||||
return db.raw.query(CompanyModel).filter_by(
|
return db.raw_session.query(CompanyModel).filter_by(
|
||||||
FtgNr=ftg_nr
|
FtgNr=ftg_nr
|
||||||
).one()
|
).one()
|
||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
|
|
@ -26,17 +26,21 @@ class Company():
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_active_customers():
|
def get_all_active_customers():
|
||||||
cust = db.raw.query(CustomerModel).filter(and_(CustomerModel.Makulerad == 0)).all()
|
cust = db.raw_session.query(CustomerModel).filter(and_(CustomerModel.Makulerad == 0)).all()
|
||||||
return [c.CompanyModel for c in cust]
|
return [c.CompanyModel for c in cust]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_customer_numbers(category_list=[10], class_list=[], filter_inactive=True):
|
def get_customers(category_list=[10], class_list=[], filter_inactive=True, filters=and_()):
|
||||||
category_in = CustomerModel.kundkategorikod.in_(category_list) if category_list else and_()
|
category_in = CustomerModel.kundkategorikod.in_(category_list) if category_list else and_()
|
||||||
class_in = CustomerModel.kundklass.in_(class_list) if class_list else and_()
|
class_in = CustomerModel.kundklass.in_(class_list) if class_list else and_()
|
||||||
inactive = and_(CustomerModel.Makulerad == 0) if filter_inactive else and_()
|
inactive = and_(CustomerModel.Makulerad == 0) if filter_inactive else and_()
|
||||||
cust = db.raw.query(CustomerModel).options(
|
return db.raw_session.query(CustomerModel).options(
|
||||||
Load(CustomerModel).noload('*')).filter(
|
Load(CompanyModel).noload('*')).filter(
|
||||||
and_(category_in, class_in, inactive)).all()
|
and_(category_in, class_in, inactive, filters)).all()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_customer_numbers(category_list=[10], class_list=[], filter_inactive=True):
|
||||||
|
cust = Company.get_customers(category_list, class_list, filter_inactive)
|
||||||
return [c.FtgNr for c in cust]
|
return [c.FtgNr for c in cust]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -45,24 +49,71 @@ class Company():
|
||||||
if ftg_nr:
|
if ftg_nr:
|
||||||
ftg_filter = CompanyModel.FtgNr.in_(ftg_nr)
|
ftg_filter = CompanyModel.FtgNr.in_(ftg_nr)
|
||||||
|
|
||||||
return db.raw.query(CompanyModel).join(CustomerModel).filter(
|
return db.raw_session.query(CompanyModel).join(CustomerModel).filter(
|
||||||
and_(ftg_filter, filter_)).order_by(
|
and_(ftg_filter, filter_)).order_by(
|
||||||
CompanyModel.FtgNr.desc()).offset(offset).limit(limit).all()
|
CompanyModel.FtgNr.desc()).offset(offset).limit(limit).all()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Should be moved to separate project with Lindvalls specific code
|
||||||
|
def update_customer_delivery_from_csv(filename='zip_codes_svhl.csv'):
|
||||||
|
SVHL_ZONES = {}
|
||||||
|
|
||||||
|
logger.info("Get customers")
|
||||||
|
customers = Company.get_customers(filters=(
|
||||||
|
and_(CustomerModel.LevSattKod == 3, CustomerModel.kundklass == None))) # noqa
|
||||||
|
logger.info("Amount of customers is %d" % len(customers))
|
||||||
|
|
||||||
|
import csv
|
||||||
|
with open(filename, newline='') as csvfile:
|
||||||
|
shelfreader = csv.reader(csvfile, delimiter=',')
|
||||||
|
headers = shelfreader.__next__()
|
||||||
|
logger.info('Found these columns: %s' % (', '.join(headers)))
|
||||||
|
for row in shelfreader:
|
||||||
|
SVHL_ZONES[row[0]] = '%s - %s' % (row[2], row[1])
|
||||||
|
|
||||||
|
logger.info('Length of zones dict is %d' % (len(SVHL_ZONES)))
|
||||||
|
|
||||||
|
customers_to_update = 0
|
||||||
|
|
||||||
|
for customer in customers:
|
||||||
|
|
||||||
|
if customer.Company.FtgLevPostNr:
|
||||||
|
FtgLevPostNr = customer.Company.FtgLevPostNr.strip().replace(" ", "")
|
||||||
|
if FtgLevPostNr and FtgLevPostNr in SVHL_ZONES:
|
||||||
|
logger.info('FtgLevPostNr: %s - %s is within SVHL zone %s' % (
|
||||||
|
customer.FtgNr, customer.Company.FtgNamn, SVHL_ZONES[FtgLevPostNr]))
|
||||||
|
customers_to_update += 1
|
||||||
|
customer.LevSattKod = 11
|
||||||
|
continue
|
||||||
|
# Return? Break?
|
||||||
|
if customer.Company.FtgPostnr:
|
||||||
|
FtgPostnr = customer.Company.FtgPostnr.strip().replace(" ", "")
|
||||||
|
if FtgPostnr and FtgPostnr in SVHL_ZONES:
|
||||||
|
logger.info('FtgPostnr: %s - %s is within SVHL zone %s' % (
|
||||||
|
customer.FtgNr, customer.Company.FtgNamn, SVHL_ZONES[FtgPostnr]))
|
||||||
|
customer.LevSattKod = 11
|
||||||
|
customers_to_update += 1
|
||||||
|
|
||||||
|
logger.info('Amount updated %d' % customers_to_update)
|
||||||
|
|
||||||
|
# db.raw_db.merge(n1)
|
||||||
|
db.raw_db.commit()
|
||||||
|
logger.info('Succesfully commited updated customers to database')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# print([column.key for column in CompanyModel.__table__.columns])
|
# print([column.key for column in CompanyModel.__table__.columns])
|
||||||
|
|
||||||
logger.info("Starting TEST")
|
# logger.info("Starting TEST")
|
||||||
# session = RawSession()
|
# session = RawSession()
|
||||||
|
|
||||||
logger.info("Testing gettings a company")
|
# logger.info("Testing gettings a company")
|
||||||
# c1 = session.query(CompanyModel).filter_by(FtgNr="179580").first()
|
# c1 = session.query(CompanyModel).filter_by(FtgNr="179580").first()
|
||||||
# print(CompanyModel)
|
# print(CompanyModel)
|
||||||
|
|
||||||
# print(CompanyModel.get_list(['406569', '179580', '2440070', '179584']))
|
# print(CompanyModel.get_list(['406569', '179580', '2440070', '179584']))
|
||||||
from pprint import pprint
|
# from pprint import pprint
|
||||||
pprint(CompanyModel.get('179584').to_dict())
|
# pprint(CompanyModel.get('179584').to_dict())
|
||||||
|
|
||||||
# c1 = CompanyModel.query.filter_by(FtgNr="406569").first()
|
# c1 = CompanyModel.query.filter_by(FtgNr="406569").first()
|
||||||
# print(c1)
|
# print(c1)
|
||||||
|
|
@ -73,3 +124,6 @@ if __name__ == '__main__':
|
||||||
# )
|
# )
|
||||||
|
|
||||||
# print(CompanyModel.get_all_active_customers()[0].CompanyModel)
|
# print(CompanyModel.get_all_active_customers()[0].CompanyModel)
|
||||||
|
|
||||||
|
logger.info("Starting")
|
||||||
|
update_customer_delivery_from_csv()
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
nose==1.3.7
|
nose==1.3.7
|
||||||
Sphinx==1.8.5
|
Sphinx==3.2.1
|
||||||
pymssql==2.1.4
|
pymssql-py38==2.1.4
|
||||||
SQLAlchemy==1.3.1
|
SQLAlchemy==1.3.22
|
||||||
sqlservice==1.1.3
|
sqlservice==1.2.1
|
||||||
PyMySQL==0.9.3
|
PyMySQL==0.10.0
|
||||||
alembic==1.0.8
|
alembic==1.4.2
|
||||||
PyYAML==5.1
|
PyYAML==5.3.1
|
||||||
|
gtin==0.1.13
|
||||||
5
setup.py
5
setup.py
|
|
@ -12,7 +12,7 @@ with open('LICENSE') as f:
|
||||||
setup(
|
setup(
|
||||||
name='pyjeeves',
|
name='pyjeeves',
|
||||||
version='0.0.1',
|
version='0.0.1',
|
||||||
description='PyJeeves syncronization module',
|
description='PyJeeves communication module',
|
||||||
long_description=readme,
|
long_description=readme,
|
||||||
author='Marcus Lindvall',
|
author='Marcus Lindvall',
|
||||||
author_email='marcus.lindvall@lindvallskaffe.se',
|
author_email='marcus.lindvall@lindvallskaffe.se',
|
||||||
|
|
@ -22,11 +22,12 @@ setup(
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'nose',
|
'nose',
|
||||||
'sphinx',
|
'sphinx',
|
||||||
'pymssql',
|
'pymssql-py38',
|
||||||
'sqlalchemy',
|
'sqlalchemy',
|
||||||
'sqlservice',
|
'sqlservice',
|
||||||
'PyMySQL',
|
'PyMySQL',
|
||||||
'alembic',
|
'alembic',
|
||||||
'pyyaml',
|
'pyyaml',
|
||||||
|
'gtin'
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue