edit : 기본 rest서버구조 추가

This commit is contained in:
2025-01-14 17:26:27 +09:00
parent e53282d7e7
commit bd28fcdca4
37 changed files with 4194 additions and 1 deletions

17
rest/app/utils/_temp.py Normal file
View File

@@ -0,0 +1,17 @@
ps_list = [
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958110","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000010","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHJ2G1","DIMS_CODE_MEANING":"H 390 x 300 x 10/16","ORD_LENGTH":14000,"LOAD_SITE_CD":"P4330","LOAD_SITE_CD_MEANING":"C구역","YD_STRE_LOC_CD":"O0211","BUNDLE_PCS_CNT":3,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":1,"PROD_WGT":1498,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":1498,"PROD_COL":3,"PROD_ROW":1,"PROD_TP":"I","PROD_THIK_1":10,"PROD_THIK_2":16,"PROD_HGHT":390,"PROD_SIDE":300,"TOT_COL_WTH":610,"TOT_ROW_HGT":406},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958111","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000020","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHH3K1","DIMS_CODE_MEANING":"H 350 x 350 x 12/19","ORD_LENGTH":12000,"LOAD_SITE_CD":"P1600","LOAD_SITE_CD_MEANING":"형강1출하장","YD_STRE_LOC_CD":"F0208","BUNDLE_PCS_CNT":2,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":1,"PROD_WGT":1644,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":1644,"PROD_COL":2,"PROD_ROW":1,"PROD_TP":"I","PROD_THIK_1":12,"PROD_THIK_2":19,"PROD_HGHT":350,"PROD_SIDE":350,"TOT_COL_WTH":531,"TOT_ROW_HGT":369},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958112","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000030","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHH3K1","DIMS_CODE_MEANING":"H 350 x 350 x 12/19","ORD_LENGTH":11000,"LOAD_SITE_CD":"P1600","LOAD_SITE_CD_MEANING":"형강1출하장","YD_STRE_LOC_CD":"K0261","BUNDLE_PCS_CNT":2,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":1,"PROD_WGT":1507,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":1507,"PROD_COL":2,"PROD_ROW":1,"PROD_TP":"I","PROD_THIK_1":12,"PROD_THIK_2":19,"PROD_HGHT":350,"PROD_SIDE":350,"TOT_COL_WTH":531,"TOT_ROW_HGT":369},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958113","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000040","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHG191","DIMS_CODE_MEANING":"H 300 x 150 x 6.5/9","ORD_LENGTH":11000,"LOAD_SITE_CD":"P4330","LOAD_SITE_CD_MEANING":"C구역","YD_STRE_LOC_CD":"O0201","BUNDLE_PCS_CNT":10,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":2,"PROD_WGT":808,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":404,"PROD_COL":2,"PROD_ROW":5,"PROD_TP":"H","PROD_THIK_1":6.5,"PROD_THIK_2":9,"PROD_HGHT":300,"PROD_SIDE":150,"TOT_COL_WTH":618,"TOT_ROW_HGT":463},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958114","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000050","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHG191","DIMS_CODE_MEANING":"H 300 x 150 x 6.5/9","ORD_LENGTH":9000,"LOAD_SITE_CD":"P4310","LOAD_SITE_CD_MEANING":"A구역","YD_STRE_LOC_CD":"Y0219","BUNDLE_PCS_CNT":10,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":1,"PROD_WGT":330,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":330,"PROD_COL":2,"PROD_ROW":5,"PROD_TP":"H","PROD_THIK_1":6.5,"PROD_THIK_2":9,"PROD_HGHT":300,"PROD_SIDE":150,"TOT_COL_WTH":618,"TOT_ROW_HGT":463},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958115","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000060","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHF3E1","DIMS_CODE_MEANING":"H 250 x 250 x 9/14","ORD_LENGTH":12000,"LOAD_SITE_CD":"P4310","LOAD_SITE_CD_MEANING":"A구역","YD_STRE_LOC_CD":"Y0205","BUNDLE_PCS_CNT":4,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":1,"PROD_WGT":869,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":869,"PROD_COL":2,"PROD_ROW":2,"PROD_TP":"H","PROD_THIK_1":9,"PROD_THIK_2":14,"PROD_HGHT":250,"PROD_SIDE":250,"TOT_COL_WTH":528,"TOT_ROW_HGT":379.5},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958116","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000070","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHE3C1","DIMS_CODE_MEANING":"H 200 x 200 x 8/12","ORD_LENGTH":11000,"LOAD_SITE_CD":"P4320","LOAD_SITE_CD_MEANING":"B구역","YD_STRE_LOC_CD":"W0233","BUNDLE_PCS_CNT":6,"BS_BD_NO":1,"PROD_PCS_PIECE_NO":0,"PROD_WGT":3294,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":549,"PROD_COL":2,"PROD_ROW":3,"PROD_TP":"H","PROD_THIK_1":8,"PROD_THIK_2":12,"PROD_HGHT":200,"PROD_SIDE":200,"TOT_COL_WTH":424,"TOT_ROW_HGT":408},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958117","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000080","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHE291","DIMS_CODE_MEANING":"H 194 x 150 x 6/9","ORD_LENGTH":12000,"LOAD_SITE_CD":"P4320","LOAD_SITE_CD_MEANING":"B구역","YD_STRE_LOC_CD":"W0201","BUNDLE_PCS_CNT":12,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":1,"PROD_WGT":367,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":367,"PROD_COL":3,"PROD_ROW":4,"PROD_TP":"H","PROD_THIK_1":6,"PROD_THIK_2":9,"PROD_HGHT":194,"PROD_SIDE":150,"TOT_COL_WTH":600,"TOT_ROW_HGT":384},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958118","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000090","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHC3A1","DIMS_CODE_MEANING":"H 150 x 150 x 7/10","ORD_LENGTH":12000,"LOAD_SITE_CD":"P4300","LOAD_SITE_CD_MEANING":"형강제품창고","YD_STRE_LOC_CD":"C0214","BUNDLE_PCS_CNT":12,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":2,"PROD_WGT":756,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":378,"PROD_COL":3,"PROD_ROW":4,"PROD_TP":"H","PROD_THIK_1":7,"PROD_THIK_2":10,"PROD_HGHT":150,"PROD_SIDE":150,"TOT_COL_WTH":470,"TOT_ROW_HGT":385.5},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958119","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007189167","ORD_LINE_NO":"000100","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHC3A1","DIMS_CODE_MEANING":"H 150 x 150 x 7/10","ORD_LENGTH":10000,"LOAD_SITE_CD":"P4300","LOAD_SITE_CD_MEANING":"형강제품창고","YD_STRE_LOC_CD":"B0204","BUNDLE_PCS_CNT":12,"BS_BD_NO":0,"PROD_PCS_PIECE_NO":3,"PROD_WGT":945,"ARR_LOC_CD":"432","ARR_LOC_CD_MEANING":"충남 천안시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5388-5588","PROD_PIECE_WGHT":315,"PROD_COL":3,"PROD_ROW":4,"PROD_TP":"H","PROD_THIK_1":7,"PROD_THIK_2":10,"PROD_HGHT":150,"PROD_SIDE":150,"TOT_COL_WTH":470,"TOT_ROW_HGT":385.5},
{"LOAD_ORD_NO":"PS202311010109","DELIVERY_ORDER_NO":"5015958122","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007191107","ORD_LINE_NO":"000030","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHF3E1","DIMS_CODE_MEANING":"H 250 x 250 x 9/14","ORD_LENGTH":10000,"LOAD_SITE_CD":"P1600","LOAD_SITE_CD_MEANING":"형강1출하장","YD_STRE_LOC_CD":"K0253","BUNDLE_PCS_CNT":4,"BS_BD_NO":4,"PROD_PCS_PIECE_NO":2,"PROD_WGT":13032,"ARR_LOC_CD":"441","ARR_LOC_CD_MEANING":"충남 당진시","VEHL_NO":"서울98바9283","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5789-1591","PROD_PIECE_WGHT":724,"PROD_COL":2,"PROD_ROW":2,"PROD_TP":"H","PROD_THIK_1":9,"PROD_THIK_2":14,"PROD_HGHT":250,"PROD_SIDE":250,"TOT_COL_WTH":528,"TOT_ROW_HGT":379.5},
# {"LOAD_ORD_NO":"PS202311010110","DELIVERY_ORDER_NO":"5015958120","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007191107","ORD_LINE_NO":"000010","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHE181","DIMS_CODE_MEANING":"H 200 x 100 x 5.5/8","ORD_LENGTH":10000,"LOAD_SITE_CD":"P4320","LOAD_SITE_CD_MEANING":"B구역","YD_STRE_LOC_CD":"V0226","BUNDLE_PCS_CNT":12,"BS_BD_NO":3,"PROD_PCS_PIECE_NO":4,"PROD_WGT":8520,"ARR_LOC_CD":"441","ARR_LOC_CD_MEANING":"충남 당진시","VEHL_NO":"경북98사1884","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5789-1591","PROD_PIECE_WGHT":213,"PROD_COL":3,"PROD_ROW":4,"PROD_TP":"H","PROD_THIK_1":5.5,"PROD_THIK_2":8,"PROD_HGHT":200,"PROD_SIDE":100,"TOT_COL_WTH":616,"TOT_ROW_HGT":258.25},
# {"LOAD_ORD_NO":"PS202311010110","DELIVERY_ORDER_NO":"5015958121","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007191107","ORD_LINE_NO":"000020","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHE3C1","DIMS_CODE_MEANING":"H 200 x 200 x 8/12","ORD_LENGTH":10000,"LOAD_SITE_CD":"P4320","LOAD_SITE_CD_MEANING":"B구역","YD_STRE_LOC_CD":"W0237","BUNDLE_PCS_CNT":6,"BS_BD_NO":2,"PROD_PCS_PIECE_NO":3,"PROD_WGT":7485,"ARR_LOC_CD":"441","ARR_LOC_CD_MEANING":"충남 당진시","VEHL_NO":"경북98사1884","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5789-1591","PROD_PIECE_WGHT":499,"PROD_COL":2,"PROD_ROW":3,"PROD_TP":"H","PROD_THIK_1":8,"PROD_THIK_2":12,"PROD_HGHT":200,"PROD_SIDE":200,"TOT_COL_WTH":424,"TOT_ROW_HGT":408},
# {"LOAD_ORD_NO":"PS202311010110","DELIVERY_ORDER_NO":"5015958122","DELIVERY_ORDER_LINE_NO":"10","ORD_NO":"3007191107","ORD_LINE_NO":"000030","ITEM_TP_CD":"S","ITEM_TP_CD_MEANING":"형강","SPEC_CD":"KS SM355A ALL","DIMS_CODE":"SHF3E1","DIMS_CODE_MEANING":"H 250 x 250 x 9/14","ORD_LENGTH":10000,"LOAD_SITE_CD":"P1600","LOAD_SITE_CD_MEANING":"형강1출하장","YD_STRE_LOC_CD":"K0253","BUNDLE_PCS_CNT":4,"BS_BD_NO":2,"PROD_PCS_PIECE_NO":3,"PROD_WGT":7964,"ARR_LOC_CD":"441","ARR_LOC_CD_MEANING":"충남 당진시","VEHL_NO":"경북98사1884","VEHICLE_TYPE":"TL01","VEHICLE_TYPE_MEANING":"트레일러 (25톤)","DELY_PHONE":"010-5789-1591","PROD_PIECE_WGHT":724,"PROD_COL":2,"PROD_ROW":2,"PROD_TP":"H","PROD_THIK_1":9,"PROD_THIK_2":14,"PROD_HGHT":250,"PROD_SIDE":250,"TOT_COL_WTH":528,"TOT_ROW_HGT":379.5}
]

View File

@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
"""
@File: date_utils.py
@Date: 2020-09-14
@author: A2TEC
@section MODIFYINFO 수정정보
- 수정자/수정일 : 수정내역
- 2022-01-14/hsj100@a2tec.co.kr : refactoring
@brief: date-utility functions
"""
from datetime import datetime, date, timedelta
_TIMEDELTA = 9
class D:
def __init__(self, *args):
self.utc_now = datetime.utcnow()
# NOTE(hsj100): utc->kst
self.timedelta = _TIMEDELTA
@classmethod
def datetime(cls, diff: int=_TIMEDELTA) -> datetime:
return datetime.utcnow() + timedelta(hours=diff) if diff > 0 else datetime.now()
@classmethod
def date(cls, diff: int=_TIMEDELTA) -> date:
return cls.datetime(diff=diff).date()
@classmethod
def date_num(cls, diff: int=_TIMEDELTA) -> int:
return int(cls.date(diff=diff).strftime('%Y%m%d'))
@classmethod
def validate(cls, date_text):
try:
datetime.strptime(date_text, '%Y-%m-%d')
except ValueError:
raise ValueError('Incorrect data format, should be YYYY-MM-DD')
@classmethod
def date_str(cls, diff: int = _TIMEDELTA) -> str:
return cls.datetime(diff=diff).strftime('%Y-%m-%dT%H:%M:%S')
@classmethod
def check_expire_date(cls, expire_date: datetime):
td = expire_date - datetime.now()
timestamp = td.total_seconds()
return timestamp

View File

@@ -0,0 +1,197 @@
from rest.app.utils._temp import ps_list
class parsingDKAPI:
def __init__(self):
# self.info_list = []
self.info_list = ps_list
self.location_list = [] # index 0 사용 안함
self.bd_type = None
self.bd_meaning = None
class bundleType:
bd = "1"
pcs = "0"
hbeam = "HBeam"
def set_api_infolist(self, list):
self.info_list = list
def location_list_parsing(self):
if not self.info_list:
raise
for i in self.info_list:
if isinstance(i, int):
pass
elif isinstance(i.get("ARR_LOC_CD"), str):
self.location_list.append(i.get("ARR_LOC_CD"))
self.location_list = [-1] + list(set(self.location_list))
def get_bd_data(self):
return (self.bd_type,self.bd_meaning)
def parsing(self):
def pcs_length_parsing(info):
import re
try:
width, height = (None, None)
name = info.get("DIMS_CODE_MEANING")
blank_name = name.replace(" ", "").split("x")
width = float(re.sub(r"[a-zA-Z]", "", blank_name[0]))
height = int(blank_name[1])
except Exception as e:
pass
finally:
return width, height
def pcs_weight_parsing(info, bd, pcs):
try:
weight, stdweight = (None, None)
weight = int(
(info.get("PROD_WGT")- (info.get("PROD_PIECE_WGHT") * info.get("BUNDLE_PCS_CNT"))* bd)
/ pcs
)
stdweight = weight
except Exception as e:
pass
finally:
return weight, stdweight
result = []
self.location_list_parsing()
if not self.info_list:
raise
for info in self.info_list:
bd = int(info.get("BS_BD_NO")) if info.get("BS_BD_NO") != None else None
pcs = int(info.get("PROD_PCS_PIECE_NO")) if info.get("PROD_PCS_PIECE_NO") != None else None
if info.get("VEHICLE_TYPE_MEANING") != None:
if self.bd_meaning:
if self.bd_meaning != info.get("VEHICLE_TYPE_MEANING"):
raise Exception("'VEHICLE_TYPE_MEANING' parsing error")
else:
self.bd_meaning = info.get("VEHICLE_TYPE_MEANING")
if info.get("VEHICLE_TYPE") != None:
if self.bd_type:
if self.bd_type != info.get("VEHICLE_TYPE"):
raise Exception("'VEHICLE_TYPE' parsing error")
else:
self.bd_type = info.get("VEHICLE_TYPE")
if isinstance(bd, int):
if bd == 0:
pass
else:
_bd_json = {
"objectType": info.get("COMMDT_NM_CD_MEANING"),
"objectSpec": info.get("DIMS_CODE_MEANING"),
"bundle": self.bundleType.bd,
"stackType": info.get("PROD_TP"),
"dest": {
"date": info.get("CONF_DUE_DATE"),
"time": info.get("CUST_ARRV_TM"),
"name": info.get("ARR_LOC_CD_MEANING"),
"code": info.get("ARR_LOC_CD"),
"no": self.location_list.index(info.get("ARR_LOC_CD")),
},
"width": info.get("TOT_COL_WTH"),
"height": info.get("TOT_ROW_HGT"),
"depth": info.get("ORD_LENGTH"),
"weight": info.get("PROD_PIECE_WGHT") * info.get("BUNDLE_PCS_CNT"),
"loadBearing": info.get("PROD_PIECE_WGHT") * info.get("BUNDLE_PCS_CNT")
, # info.get("포장단중코드"),
"stdNum": info.get("BUNDLE_PCS_CNT"),
"stdWeight": info.get("PROD_PIECE_WGHT"),
"widthNum": info.get("PROD_COL"),
"heightNum": info.get("PROD_ROW"),
"addInfo1": (
info.get("PROD_THIK_1")
if info.get("COMMDT_NM_CD_MEANING") == self.hbeam
else 0
),
"addInfo2": (
info.get("PROD_THIK_2")
if info.get("COMMDT_NM_CD_MEANING") == self.hbeam
else 0
),
"addInfo3": 0,
"addInfo4": 0,
"addInfo5": 0,
"addInfo6": 0,
"addInfo7": 0,
"addInfo8": 0,
"addInfo9": 0,
}
for i in range(bd):
result.append(_bd_json)
if isinstance(pcs, int):
if pcs == 0:
pass
else:
width, height = pcs_length_parsing(info)
weight, stdweight = pcs_weight_parsing(info=info, bd=bd, pcs=pcs)
_pcs_json = {
"objectType": info.get("COMMDT_NM_CD_MEANING"),
"objectSpec": info.get("DIMS_CODE_MEANING"),
"bundle": self.bundleType.pcs,
"stackType": "0",
"dest": {
"date": info.get("CONF_DUE_DATE"),
"time": info.get("CUST_ARRV_TM"),
"name": info.get("ARR_LOC_CD_MEANING"),
"code": info.get("ARR_LOC_CD"),
"no": self.location_list.index(info.get("ARR_LOC_CD")),
},
"width": width,
"height": height,
"depth": info.get("ORD_LENGTH"),
"weight": weight,
"loadBearing": weight, # info.get("포장단중코드"),
"stdNum": 1,
"stdWeight": stdweight,
"widthNum": 1,
"heightNum": 1,
"addInfo1": (
info.get("PROD_THIK_1")
if info.get("COMMDT_NM_CD_MEANING") == self.hbeam
else 0
),
"addInfo2": (
info.get("PROD_THIK_2")
if info.get("COMMDT_NM_CD_MEANING") == self.hbeam
else 0
),
"addInfo3": 0,
"addInfo4": 0,
"addInfo5": 0,
"addInfo6": 0,
"addInfo7": 0,
"addInfo8": 0,
"addInfo9": 0,
}
for i in range(pcs):
result.append(_pcs_json)
return result
if __name__ == "__main__":
a = parsingDKAPI()
b = a.parsing()
pass

205
rest/app/utils/extra.py Normal file
View File

@@ -0,0 +1,205 @@
# -*- coding: utf-8 -*-
"""
@File: extra.py
@Date: 2020-09-14
@author: A2TEC
@section MODIFYINFO 수정정보
- 수정자/수정일 : 수정내역
- 2022-01-14/hsj100@a2tec.co.kr : refactoring
@brief: extra functions
"""
from hashlib import md5
from base64 import b64decode
from base64 import b64encode
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from cryptography.fernet import Fernet # symmetric encryption
# mail test
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from itertools import groupby
from operator import attrgetter
import uuid
from rest.app.common.consts import NUM_RETRY_UUID_GEN, SMTP_HOST, SMTP_PORT
from rest.app.utils.date_utils import D
from rest.app import models as M
from rest.app.common.consts import AES_CBC_PUBLIC_KEY, AES_CBC_IV, FERNET_SECRET_KEY
async def send_mail(sender, sender_pw, title, recipient, contents_plain, contents_html, cc_list, smtp_host=SMTP_HOST, smtp_port=SMTP_PORT):
"""
구글 계정사용시 : 보안 수준이 낮은 앱에서의 접근 활성화
:return:
None: success
Str. Message: error
"""
try:
# check parameters
if not sender:
raise Exception('invalid sender')
if not title:
raise Exception('invalid title')
if not recipient:
raise Exception('invalid recipient')
# sender info.
# sender = consts.ADMIN_INIT_ACCOUNT_INFO.email
# sender_pw = consts.ADMIN_INIT_ACCOUNT_INFO.email_pw
# message
msg = MIMEMultipart()
msg['From'] = sender
msg['To'] = recipient
if cc_list:
list_cc = cc_list
str_cc = ','.join(list_cc)
msg['Cc'] = str_cc
msg['Subject'] = title
if contents_plain:
msg.attach(MIMEText(contents_plain, 'plain'))
if contents_html:
msg.attach(MIMEText(contents_html, 'html'))
# smtp server
smtp_server = smtplib.SMTP(host=smtp_host, port=smtp_port)
smtp_server.ehlo()
smtp_server.starttls()
smtp_server.ehlo()
smtp_server.login(sender, sender_pw)
smtp_server.send_message(msg)
smtp_server.quit()
return None
except Exception as e:
return str(e)
def query_to_groupby(query_result, key, first=False):
"""
쿼리 결과물(list)을 항목값(key)으로 그룹화한다.
:param query_result: 쿼리 결과 리스트
:param key: 그룹 항목값
:return: dict
"""
group_info = dict()
for k, g in groupby(query_result, attrgetter(key)):
if k not in group_info:
if not first:
group_info[k] = list(g)
else:
group_info[k] = list(g)[0]
else:
if not first:
group_info[k].extend(list(g))
return group_info
def query_to_groupby_date(query_result, key):
"""
쿼리 결과물(list)을 항목값(key)으로 그룹화한다.
:param query_result: 쿼리 결과 리스트
:param key: 그룹 항목값
:return: dict
"""
group_info = dict()
for k, g in groupby(query_result, attrgetter(key)):
day_str = k.strftime("%Y-%m-%d")
if day_str not in group_info:
group_info[day_str] = list(g)
else:
group_info[day_str].extend(list(g))
return group_info
class FernetCrypto:
def __init__(self, key=FERNET_SECRET_KEY):
self.key = key
self.f = Fernet(self.key)
def encrypt(self, data, is_out_string=True):
if isinstance(data, bytes):
ou = self.f.encrypt(data) # 바이트형태이면 바로 암호화
else:
ou = self.f.encrypt(data.encode('utf-8')) # 인코딩 후 암호화
if is_out_string is True:
return ou.decode('utf-8') # 출력이 문자열이면 디코딩 후 반환
else:
return ou
def decrypt(self, data, is_out_string=True):
if isinstance(data, bytes):
ou = self.f.decrypt(data) # 바이트형태이면 바로 복호화
else:
ou = self.f.decrypt(data.encode('utf-8')) # 인코딩 후 복호화
if is_out_string is True:
return ou.decode('utf-8') # 출력이 문자열이면 디코딩 후 반환
else:
return ou
class AESCryptoCBC:
def __init__(self, key=AES_CBC_PUBLIC_KEY, iv=AES_CBC_IV):
# Initial vector를 0으로 초기화하여 16바이트 할당함
# iv = chr(0) * 16 #pycrypto 기준
# iv = bytes([0x00] * 16) #pycryptodomex 기준
# aes cbc 생성
self.key = key
self.iv = iv
self.crypto = AES.new(self.key, AES.MODE_CBC, self.iv)
def encrypt(self, data):
# 암호화 message는 16의 배수여야 한다.
# enc = self.crypto.encrypt(data)
# return enc
enc = self.crypto.encrypt(pad(data, AES.block_size))
return b64encode(enc)
def decrypt(self, enc):
# 복호화 enc는 16의 배수여야 한다.
# dec = self.crypto.decrypt(enc)
# return dec
enc = b64decode(enc)
dec = self.crypto.decrypt(enc)
return unpad(dec, AES.block_size)
class AESCipher:
def __init__(self, key):
# self.key = md5(key.encode('utf8')).digest()
self.key = bytes(key.encode('utf-8'))
def encrypt(self, data):
# iv = get_random_bytes(AES.block_size)
iv = bytes('daooldns12345678'.encode('utf-8'))
self.cipher = AES.new(self.key, AES.MODE_CBC, iv)
t = b64encode(self.cipher.encrypt(pad(data.encode('utf-8'), AES.block_size)))
return b64encode(iv + self.cipher.encrypt(pad(data.encode('utf-8'), AES.block_size)))
def decrypt(self, data):
raw = b64decode(data)
self.cipher = AES.new(self.key, AES.MODE_CBC, raw[:AES.block_size])
return unpad(self.cipher.decrypt(raw[AES.block_size:]), AES.block_size)
def cls_list_to_dict_list(list):
"""
list 내부 element가 dict로 변환 가능한 class일경우
내부 element를 dict 로 변경
"""
_result = []
for i in list:
if isinstance(i, dict):
_result = list
break
_result.append(i.dict())
return _result

65
rest/app/utils/logger.py Normal file
View File

@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
"""
@File: logger.py
@Date: 2020-09-14
@author: A2TEC
@section MODIFYINFO 수정정보
- 수정자/수정일 : 수정내역
- 2022-01-14/hsj100@a2tec.co.kr : refactoring
@brief: logger
"""
import json
import logging
from datetime import timedelta, datetime
from time import time
from fastapi.requests import Request
from fastapi import Body
from fastapi.logger import logger
logger.setLevel(logging.INFO)
async def api_logger(request: Request, response=None, error=None):
time_format = '%Y/%m/%d %H:%M:%S'
t = time() - request.state.start
status_code = error.status_code if error else response.status_code
error_log = None
user = request.state.user
if error:
if request.state.inspect:
frame = request.state.inspect
error_file = frame.f_code.co_filename
error_func = frame.f_code.co_name
error_line = frame.f_lineno
else:
error_func = error_file = error_line = 'UNKNOWN'
error_log = dict(
errorFunc=error_func,
location='{} line in {}'.format(str(error_line), error_file),
raised=str(error.__class__.__name__),
msg=str(error.ex),
)
account = user.account.split('@') if user and user.account else None
user_log = dict(
client=request.state.ip,
user=user.id if user and user.id else None,
account='**' + account[0][2:-1] + '*@' + account[1] if user and user.account else None,
)
log_dict = dict(
url=request.url.hostname + request.url.path,
method=str(request.method),
statusCode=status_code,
errorDetail=error_log,
client=user_log,
processedTime=str(round(t * 1000, 5)) + 'ms',
datetimeUTC=datetime.utcnow().strftime(time_format),
datetimeKST=(datetime.utcnow() + timedelta(hours=9)).strftime(time_format),
)
if error and error.status_code >= 500:
logger.error(json.dumps(log_dict))
else:
logger.info(json.dumps(log_dict))

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
"""
@File: query_utils.py
@Date: 2020-09-14
@author: A2TEC
@section MODIFYINFO 수정정보
- 수정자/수정일 : 수정내역
- 2022-01-14/hsj100@a2tec.co.kr : refactoring
@brief: query-utility functions
"""
from typing import List
def to_dict(model, *args, exclude: List = None):
q_dict = {}
for c in model.__table__.columns:
if not args or c.name in args:
if not exclude or c.name not in exclude:
q_dict[c.name] = getattr(model, c.name)
return q_dict