Last worked version

This commit is contained in:
2021-06-09 16:25:48 +09:00
commit fae4a6fcf0
4 changed files with 823 additions and 0 deletions

167
app.py Normal file
View File

@ -0,0 +1,167 @@
from sqlalchemy.orm import sessionmaker
from dbmodels import DBEngine, FZ54, metadata, FZ54Details, Sell, PayloadTable, ErrorTable, DocTable, AtolTable
from atol import Atol
from basemodels import Error, SellBaseModel, DocModel
from time import sleep
from datetime import datetime
import json
def db_init():
server = '172.27.31.195:1433'
user = 'sa'
password = '159357'
dbname = 'fz54'
db = DBEngine(server, dbname, user, password)
dbname = 'fz54_details'
dbinfo = DBEngine(server, dbname, user, password)
return db, dbinfo
def main():
db_fz, db_fzdetails = db_init()
models = FZ54(db_fz)
metadata.create_all(db_fz.engine)
details = FZ54Details(db_fzdetails)
return models, details
def sell(fz, fzd):
res = Sell(fz, fzd)
dicts = res.make()
return dicts
def clear_dict(d):
if d is None:
return None
elif isinstance(d, list):
return list(filter(lambda x: x is not None, map(clear_dict, d)))
elif not isinstance(d, dict):
return d
else:
r = dict(
filter(lambda x: x[1] is not None,
map(lambda x: (x[0], clear_dict(x[1])),
d.items())))
if not bool(r):
return None
return r
def connection_db(models):
Session = sessionmaker(autocommit=False, bind=models.db.engine)
return Session()
def sell_items(sell_base_models, models, token):
for sell_base_model in sell_base_models:
sbm = clear_dict(sell_base_model.dict())
ext_id = sbm.get('external_id')
session1 = Atol(token)
sss = connection_db(models)
try:
sell = session1.set_sell(sbm)
sell['external_id'] = ext_id
err_sell = sell.pop('error')
doc_model = clear_dict(sell)
try:
atol = AtolTable(**doc_model)
sss.add(atol)
sss.commit()
except Exception as e:
sss.rollback()
except Exception:
error = err_sell
error['external_id'] = ext_id
err = ErrorTable(**error)
zz = connection_db(models)
try:
zz.add(err)
zz.commit()
except Exception as e:
zz.rollback()
finally:
zz.close()
finally:
sss.close()
sleep(2)
def get_receipt(uuid, ext_id, models, atol_session):
sell = atol_session.get_reciepts(uuid)
session = connection_db(models)
try:
doc_dict = DocModel(**sell)
doc_model = doc_dict.dict()
error = doc_model.pop('error')
payload = doc_model.pop('payload')
if type(error) is dict:
try:
error['external_id'] = ext_id
err = ErrorTable(**error)
except Exception as e:
print(e)
if type(payload) is dict:
try:
payload['external_id'] = ext_id
pay = PayloadTable(**payload)
except Exception as e:
print(e)
doc = DocTable(**doc_model)
if type(payload) is dict:
session.add(doc)
session.add(pay)
session.commit()
elif type(error) is dict:
session.add(doc)
session.add(err)
session.commit()
print(doc_dict)
except Exception as e:
print(e)
print(doc_dict)
error = sell.get('error')
error['external_id'] = ext_id
err = ErrorTable(**error)
ss = session
try:
ss.add(err)
ss.commit()
except Exception as e:
print(e)
ss.rollback()
finally:
session.close()
def remove_tuple(lst):
return [item[0] for item in lst]
if __name__ == "__main__":
starttime = datetime.now()
models, details = main()
token = models.get_token()
sell_models = sell(models, details)
sell_base_models = SellBaseModel().parse(db_dict_list=sell_models)
inst_list_query = 'SELECT external_id FROM sell WHERE external_id NOT IN(\
SELECT external_id FROM atol_receipt )\
ORDER BY [timestamp]'
inst_list = connection_db(models).execute(inst_list_query).fetchall()
sell_base_models = [model for model in sell_base_models if model.dict().get(
'external_id') in remove_tuple(inst_list)]
sell_items(sell_base_models, models, token.get('token'))
endfirsttime = datetime.now()
deltatime = starttime - endfirsttime
print(f'прошло {deltatime.seconds}')
receipt_list = connection_db(models).execute(
"SELECT external_id, uuid FROM atol_receipt WHERE external_id not in (select external_id FROM docs)")
for rec in list(receipt_list):
sleep(2)
ext_id, uuid = rec
get_receipt(uuid, ext_id, models, Atol(token.get('token')))
donetime = datetime.now()
deltaendtime = starttime - donetime
print(f'прошло {deltaendtime.seconds}')

51
atol.py Normal file
View File

@ -0,0 +1,51 @@
import requests
import json
#{'uuid': '0dc8ac69-74e3-4657-b590-d1efebc84594', 'status': 'wait', 'error': None, 'timestamp': '13.04.2021 14:43:07'}
class Atol:
def __init__(self, token):
self.token = token
# Вызовы функций
self.load_info()
# self.get_token()
def load_info(self):
self.url = "https://online.atol.ru/possystem/v4/"
self.group_id = 'jkhsakha-ru_3289'
def get_headers(self):
headers_dict = {
"Content-type": "application/json",
"charset": "utf-8",
"Token": self.token, }
return headers_dict
def get_request(self, method, url, data):
if method == "post":
r = requests.post(self.url+url, data=json.dumps(data),
headers=self.get_headers())
else:
r = requests.get(self.url+url, headers=self.get_headers())
r.encoding = "utf-8"
return json.loads(r.text)
def get_token(self):
d = {"login": self.login, "pass": self.password}
self.token, _, self.timestamp = self.get_request(
"post", "getToken", d).values()
print(self.token)
def set_sell(self, reciept):
s = self.get_request('post', self.group_id+'/sell', reciept)
return s
def get_reciepts(self, uuid):
r = self.get_request('get', self.group_id+'/' + 'report/'+uuid, None)
return r
if __name__ == "__main__":
session1 = Atol()
print(f"token = '{session1.token},\ntimestamp= '{session1.timestamp}'")

209
basemodels.py Normal file
View File

@ -0,0 +1,209 @@
from typing import List, Optional, Dict
from pydantic import BaseModel, Field, confloat, constr
class SumNumberTwoFormat(BaseModel):
__root__: Optional[confloat(ge=0.0, le=100000000.0, multiple_of=0.01)]
class NumberPrice(BaseModel):
__root__: confloat(ge=0.0, le=42949673.0, multiple_of=0.01)
class PhoneNumber(BaseModel):
__root__: constr(regex=r'^([^\s\\]{0,17}|\+[^\s\\]{1,18})$')
class NumberTwoFormat(BaseModel):
__root__: confloat(ge=0.0, le=100000000.0, multiple_of=0.01)
class NumberThreeFormat(BaseModel):
__root__: confloat(ge=0.0, le=100000.0, multiple_of=0.001)
class Service(BaseModel):
callback_url: Optional[constr(max_length=256)] = None
class Warnings(BaseModel):
callback_url: str = None
class PayingAgent(BaseModel):
operation: Optional[str] = None
phones: Optional[List[PhoneNumber]] = None
class SupplierInfo(BaseModel):
phones: Optional[List[PhoneNumber]] = None
class ReceivePaymentsOperator(BaseModel):
phones: Optional[List[PhoneNumber]] = None
class MoneyTransferOperator(BaseModel):
phones: Optional[List[PhoneNumber]] = None
name: Optional[str] = None
address: Optional[str] = None
inn: Optional[constr(regex=r'(^[0-9]{10}$)|(^[0-9]{12}$)')] = None
class Company(BaseModel):
email: Optional[constr(max_length=64)] = None
sno: Optional[str] = None
inn: constr(max_length=12)
payment_address: constr(max_length=256)
class ClientItem(BaseModel):
email: constr(max_length=64) = None
phone: Optional[constr(max_length=64)] = None
class AdditionalUserProps(BaseModel):
name: constr(max_length=64)
value: constr(max_length=256)
class AgentInfo(BaseModel):
type: Optional[str] = None
paying_agent: Optional[PayingAgent] = None
receive_payments_operator: Optional[ReceivePaymentsOperator] = None
money_transfer_operator: Optional[MoneyTransferOperator] = None
class Error(BaseModel):
error_id: Optional[str] = None
code: int
text: str
type: Optional[str] = None
class Payload(BaseModel):
fiscal_receipt_number: int
shift_number: int
receipt_datetime: str
total: float
fn_number: str
ecr_registration_number: str
fiscal_document_number: int
fiscal_document_attribute: int
fns_site: str
class Vat(BaseModel):
type: Optional[str] = None
sum: Optional[SumNumberTwoFormat] = None
class CorrectionInfo(BaseModel):
type: str
base_date: str
base_number: str
class Payment(BaseModel):
type: int
sum: SumNumberTwoFormat
class Item(BaseModel):
name: str
price: NumberPrice
quantity: NumberThreeFormat
sum: SumNumberTwoFormat
measurement_unit: Optional[constr(max_length=16)] = None
payment_method: Optional[str] = None
payment_object: Optional[str] = None
nomenclature_code: Optional[str] = None
vat: Optional[Vat] = None
agent_info: Optional[AgentInfo] = None
supplier_info: Optional[SupplierInfo] = None
user_data: Optional[constr(max_length=64)] = None
excise: Optional[confloat(ge=0.0)] = None
country_code: Optional[constr(
regex=r'^[0-9]*$', min_length=1, max_length=3)] = None
declaration_number: Optional[constr(min_length=1, max_length=32)] = None
class Receipt(BaseModel):
client: ClientItem
company: Company
agent_info: Optional[AgentInfo] = None
supplier_info: Optional[SupplierInfo] = None
items: List[Item] = Field(..., min_items=1)
payments: List[Payment] = Field(..., max_items=10, min_items=1)
vats: Optional[List[Vat]] = Field(None, max_items=6, min_items=1)
total: NumberTwoFormat
additional_check_props: Optional[constr(max_length=16)] = None
cashier: Optional[constr(max_length=64)] = None
additional_user_props: Optional[AdditionalUserProps] = None
class Correction(BaseModel):
company: Company
cashier: Optional[constr(max_length=64)] = None
correction_info: CorrectionInfo
payments: List[int] = Field(..., max_items=10, min_items=1)
vats: List[Vat] = Field(..., max_items=6, min_items=1)
class DocModel(BaseModel):
uuid: str
timestamp: str
group_code: str
daemon_code: str
device_code: str
external_id: Optional[str] = None
callback_url: Optional[str] = None
status: Optional[str] = None
error: Error = None
warnings: Optional[Warnings] = None
payload: Payload = None
class SellModel(BaseModel):
external_id: constr(max_length=128)
receipt: Receipt
service: Optional[Service] = None
timestamp: str
class CorrectionModel(BaseModel):
timestamp: str
external_id: constr(max_length=128)
service: Optional[Service] = None
correction: Correction
class SellBaseModel(BaseModel):
def parse(self, db_dict_list):
sell_list = []
for db_dict in db_dict_list:
receipt = db_dict['reciept']
sell = db_dict['sell']
vats = db_dict['vats']
payments = db_dict['payments']
items = db_dict['items']
company = db_dict['company']
client = db_dict['client']
items_model = [Item(**item) for item in items]
payments_model = [Payment(**payment) for payment in payments]
vats_model = [Vat(**vat) for vat in vats]
receipt['client'] = ClientItem(
**client if client.get('phone') != None else {'email': 'test@test.ru'})
receipt['vats'] = vats_model
receipt['items'] = items_model
receipt['payments'] = payments_model
receipt['company'] = Company(**company)
receipt_model = Receipt(**receipt)
sell['receipt'] = receipt_model
sell['timestamp'] = sell['timestamp'].strftime(
'%d.%m.%Y %H:%M:%S')
sellmodel = SellModel(**sell)
sell_list.append(sellmodel)
return sell_list

396
dbmodels.py Normal file
View File

@ -0,0 +1,396 @@
from requests.sessions import session
from basemodels import Company
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine, Table, Column, engine
from sqlalchemy.sql.sqltypes import DateTime
from sqlalchemy.orm import sessionmaker
from sqlalchemy.types import BigInteger, Integer, String, Numeric
import datetime
import pyodbc
Base = declarative_base()
metadata = Base.metadata
class DBEngine:
def __init__(self, server, dbname, user, password):
self.dbname = dbname
self.user = user
self.password = password
self.server = server
self.get_mssql_engine()
def get_mssql_engine(self):
query = f'mssql+pyodbc://{self.user}:{self.password}@{self.server}/{self.dbname}?driver=SQL+Server'
self.engine = create_engine(query)
class DBModel(DBEngine):
def __init__(self, db: DBEngine, tablename, *args):
self.engine = db.engine
self.filter_args = args
self.table = self.set_table(tablename)
self.data = self.get_dict_with_columns()
def set_table(self, tablename):
table = Table(
tablename,
metadata,
autoload_with=self.engine
)
return table
def result_proxy_to_Dict(self, results) -> dict:
d, a = {}, []
for rowproxy in results:
# rowproxy.items() returns an array like [(key0, value0), (key1, value1)]
for column, value in rowproxy.items():
# build up the dictionary
d = {**d, **{column: value}}
a.append(d)
return a
def get_dict_with_columns(self):
filter_filter = self.filter_args if len(self.filter_args) > 0 else True
table_values = self.engine.execute(
self.table.select().where(filter_filter))
return self.result_proxy_to_Dict(table_values)
class FZ54:
def __init__(self, db: DBEngine):
self.db = db
self.datas = {}
self.dicts = {}
self.get_datas()
def get_datas(self):
tables = {
'agents': ('id_agent', 'all'),
'agents_to_kvar': ('kod_postav', 'id_agent'),
'company_sno': ('id', 'name'),
'operation': ('id', 'name'),
'operator': ('id_operator', 'name'),
'payment_method': ('id', 'name'),
'payment_object': ('id', 'name'),
'payment_object_vat_type': ('id', 'name'),
'payment_type': ('id', 'name'),
'providers': ('id_provider', 'all'),
'providers_to_kvar': ('kod_postav', 'id_provider'),
'services': ('id_service', 'all'),
'units': ('id_unit', 'sname'),
}
self.datas = {tablename: DBModel(
self.db, tablename).data for tablename in tables.keys()}
self.dicts = {
table[0]: self.make_dict(table)
for table in tables.items()
}
def get_token(self):
ss = self.db.engine.execute("SELECT token FROM dbo.vAtolToken")
return {'token': list(ss)[0][0]}
def make_dict(self, dic):
tablename, values = dic
key, value = values
return {row.get(key): row if value == 'all' else row.get(value)
for row in self.datas.get(tablename)}
class FZ54Details:
def __init__(self, db: DBEngine):
self.db = db
self.datas = {}
self.get_datas()
def get_datas(self):
tables = ['payment_details']
self.datas = {tablename: DBModel(
self.db, tablename).data for tablename in tables}
def get_group(self, ids):
dd = {}
for id in ids:
ext_id = id.get('external_id')
values = dd.get(ext_id)
if values is None:
res_val = []
else:
res_val = values
res_val.append(id)
dd[ext_id] = res_val
return dd
class RecieptTable(Base):
__table__ = Table(
'reciepts',
metadata,
Column('external_id', String(length=128), primary_key=True),
Column('company', Integer),
Column('agent_info', Integer),
Column('supplier_info', Integer),
Column('items', String(length=128)),
Column('payments', String(length=128)),
Column('vats', String(length=128)),
Column('total', Numeric(12, 2)),
Column('additional_check_props', String),
Column('cashier', Integer),
Column('additional_user_props', Integer)
)
class ItemsTable(Base):
__table__ = Table(
'items',
metadata,
Column('id', BigInteger, primary_key=True),
Column('external_id', String(length=128)),
Column('name', String(length=255)),
Column('price', Numeric(12, 2)),
Column('quantity', Numeric(10, 2)),
Column('sum', Numeric(12, 2)),
Column('measurement_unit', String(length=16)),
Column('payment_method', String(length=10)),
Column('payment_object', String(length=10)),
Column('nomenclature_code', String(length=150)),
Column('vat', String(length=10)),
Column('agent_info', Integer),
Column('supplier_info', Integer),
Column('user_data', String(length=64)),
Column('excise', Numeric(10, 2)),
Column('country_code', String(length=3)),
Column('declaration_number', String(length=32))
)
class PaymentTable(Base):
__table__ = Table(
'payments',
metadata,
Column('id', BigInteger, primary_key=True),
Column('external_id', String(length=128)),
Column('type', Integer),
Column('sum', Numeric(12, 2)),
)
class CorrectionInfoTable(Base):
__table__ = Table(
'correction_info',
metadata,
Column('external_id', String(length=128), primary_key=True),
Column('type', String(length=10)),
Column('base_date', String(length=128)),
Column('base_number', String(length=128)),
)
class VatTable(Base):
__table__ = Table(
'vats',
metadata,
Column('id', BigInteger, primary_key=True),
Column('external_id', String(length=128)),
Column('type', String(length=10)),
Column('sum', Numeric(12, 2)),
)
class ErrorTable(Base):
__table__ = Table(
'errors',
metadata,
Column('external_id', String(length=128), primary_key=True),
Column('error_id', String(length=128)),
Column('code', Integer),
Column('text', String(length=250)),
Column('type', String(length=10)),
)
class AgentInfoTable(Base):
__table__ = Table(
'agent_info',
metadata,
Column('external_id', String(length=128), primary_key=True),
Column('type', String(length=10)),
Column('paying_agent', Integer),
Column('recieve_payments_operator', Integer),
Column('money_tranfer_operator', Integer),
)
class DocTable(Base):
__table__ = Table(
'docs',
metadata,
Column('uuid', String(length=128), primary_key=True),
Column('timestamp', String(length=128)),
Column('group_code', String(length=128)),
Column('daemon_code', String(length=128)),
Column('device_code', String(length=128)),
Column('external_id', String(length=128)),
Column('callback_url', String(length=128)),
Column('status', String(length=128)),
Column('warnings', String(length=128)),
)
class AtolTable(Base):
__table__ = Table(
'atol_receipt',
metadata,
Column('uuid', String(length=128), primary_key=True),
Column('timestamp', String(length=128)),
Column('external_id', String(length=128)),
Column('status', String(length=128)),
)
class PayloadTable(Base):
__table__ = Table(
'payloads',
metadata,
Column('external_id', String(128), primary_key=True),
Column('fiscal_receipt_number', BigInteger),
Column('shift_number', BigInteger),
Column('receipt_datetime', String(length=128)),
Column('total', Numeric(12, 2)),
Column('fn_number', String(length=128)),
Column('ecr_registration_number', String(length=128)),
Column('fiscal_document_number', BigInteger),
Column('fiscal_document_attribute', BigInteger),
Column('fns_site', String(length=128)),
)
class SellTable(Base):
__table__ = Table(
'sell',
metadata,
Column('external_id', String(length=128), primary_key=True),
Column('service', String(length=16)),
Column('reciept', String(length=128)),
Column('timestamp', DateTime)
)
class Sell:
def __init__(self, FZ54, FZ54Details):
self.fz = FZ54
self.fzd = FZ54Details
self.Session = sessionmaker(bind=self.fz.db.engine)
def make(self):
ids = self.fzd.datas['payment_details']
ids_filtered = [id for id in ids if id['month'] == 3]
dd = self.fzd.get_group(ids_filtered)
timestamp = datetime.datetime(2021, 3, 10, 0, 0, 0)
res = []
for ext_id, value in dd.items():
ext_id = ext_id.lower()
val = value[0]
total = 0.0
timestamp = timestamp + datetime.timedelta(seconds=1)
vats = {}
payments = {}
val_items = []
for i in value:
it = self.fz.dicts['services'].get(i.get('id_item'))
summa = i['summa']
vat = i['vat']
method = i['payment_method']
total += summa
if vat > 1:
summ_vat = vats.get(
self.fz.dicts['payment_object_vat_type'].get(vat))
vats[self.fz.dicts['payment_object_vat_type'].get(
vat)] = summ_vat + round(summa*0.2, 2) if type(summ_vat) is float else 0.0 + round(summa*0.2, 2)
if method in (5, 6, 7):
summ_pay3 = payments.get(3)
payments[3] = summ_pay3 + \
summa if type(summ_pay3) is float else 0.0 + summa
if method in (1, 2, 3):
summ_pay2 = payments.get(2)
payments[2] = summ_pay2 + \
summa if type(summ_pay2) is float else 0.0 + summa
if method in (4, 5):
summ_pay1 = payments.get(1)
payments[1] = summ_pay1 + \
summa if type(summ_pay1) is float else 0.0 + summa
item = ItemsTable(**{
'external_id': ext_id,
'name': it.get('sname'),
'price': i['price'],
'quantity': i['quantity'],
'sum': summa,
'measurement_unit': self.fz.dicts['units'].get(it['id_unit']),
'payment_method': self.fz.dicts['payment_method'].get(method),
'payment_object': self.fz.dicts['payment_object'].get(i['payment_object']),
'vat': self.fz.dicts['payment_object_vat_type'].get(vat),
'agent_info': i['agent_type'],
'supplier_info': None if i['agent_type'] == None else i['supplier_info']
})
val_items.append(item)
vts = [VatTable(**{'external_id': ext_id, 'type': key, 'sum': round(value, 2)})
for key, value in vats.items()]
pmnts = [PaymentTable(**{'external_id': ext_id, 'type': key, 'sum': round(value, 2)})
for key, value in payments.items()]
sell = SellTable(**{'external_id': ext_id, 'service': None,
'reciept': ext_id, 'timestamp': timestamp})
comp = self.fz.dicts['providers'].get(val['id_company'])
company = {}
company['inn'] = comp.get('inn')
company['email'] = 'ocnkp@jkhsakha.ru'
company['payment_address'] = 'http://jkhsakha.ru/'
company['sno'] = 'osn'
phone = val.get('phone')
reciept = RecieptTable(**
{
'external_id': ext_id,
'company': val['id_company'],
'agent_info': val['agent_type'],
'supplier_info': None if val['agent_type'] == None else val['supplier_info'],
'items': ext_id,
'payments': ext_id,
'vats': ext_id,
'total': round(total, 2)
})
"""
session = self.Session()
for vt in vts:
session.add(vt)
for vali in val_items:
session.add(vali)
for pmnt in pmnts:
session.add(pmnt)
session.add(sell)
session.add(reciept)
session.commit()
"""
mod_val_item = []
for val_item in val_items:
dict_val = val_item.__dict__
dict_val['vat'] = {'type': dict_val.get('vat')}
mod_val_item.append(dict_val)
row_dict = {
'reciept': reciept.__dict__,
'sell': sell.__dict__,
'vats': [vt.__dict__ for vt in vts],
'payments': [pmnt.__dict__ for pmnt in pmnts],
'items': mod_val_item,
'company': company,
'client': {'phone': phone}
}
res.append(row_dict)
return res