import os
import requests
import json
import math
import time
import sqlite3
import hashlib
from datetime import datetime
from json import dumps, loads
from urllib.parse import urlencode
from k3cloud_webapi_sdk.main import K3CloudApiSdk
# 客如云常量
BASE_URL = "https://openapi.keruyun.com"
APP_KEY = '45c9f979da976e5f63af39f70a24ff00'
APP_SECRET = 'd9871c47632948c11587b4203f496f24'
BRAN_ID = '34812143'
TOKEN = '5c61d3a18a713b008ff123f06e087315'
DB_FILE = r'E:\项目工程\始运-办公自动化\客如云_数据同步\数据文件\kry_sync_data.db'
# 税账
api_sdk_sz = K3CloudApiSdk()
api_sdk_sz.InitConfig('6453905b9418d9',
'demo1',
'272565_ScaN1csJ4nlUW9wK0dXtUYyE5M6b2KkO',
'92d7536dafd14faaad5d26452ccecbda',
'http://8.134.13.55:8090/k3cloud', # 私有云填写
2052, # 私有云填写
100) # 私有云填写
# 经营
api_sdk_jy = K3CloudApiSdk()
api_sdk_jy.InitConfig('627b29a99c6162',
'demo1',
'229496_XZ6N4ZsL4Jk+3VTu53RAUY8t0qxVxBoI',
'81d9155cf1a647f6b62173b14efb2f04',
'http://8.134.13.55:8090/k3cloud', # 私有云填写
2052, # 私有云填写
100)
# 客如云访问处理
def create_sign(appKey, shopIdenty=None, brandId=None, timestamp=None, version='2.0', body=None):
"""创建签名"""
# 准备参数
# if body is None:
params = {
'appKey': appKey,
'brandId': BRAN_ID,
'version': version,
'timestamp': timestamp,
}
# 根据情况添加shopIdenty或brandId
if shopIdenty:
params['shopIdenty'] = str(shopIdenty)
elif brandId:
params['brandId'] = str(brandId)
# 排序并拼接公共参数
sorted_params = ''.join([f"{k}{params[k]}" for k in sorted(params)])
# 拼接body(如果有)
body_str = ''
if body:
body_str = json.dumps(body, separators=(',', ':'))
# 最终拼接字符串
sign_str = f"{sorted_params}body{body_str}{TOKEN}"
else:
sign_str = f"{sorted_params}{body_str}{TOKEN}"
# SHA-256加密
sign = hashlib.sha256(sign_str.encode()).hexdigest()
return sign
def call_api(endpoint, appKey, shopIdenty=None, brandId=None, body=None):
"""调用API"""
timestamp = int(time.time() * 1000)
sign = create_sign(appKey, shopIdenty, brandId, timestamp, body=body)
# 构建请求URL
url = f"{BASE_URL}{endpoint}?appKey={appKey}"
if shopIdenty:
url += f"&shopIdenty={shopIdenty}"
elif brandId:
url += f"&brandId={brandId}"
url += f"&version=2.0×tamp={timestamp}&sign={sign}"
# 发送POST请求
response = requests.post(
url=url,
headers={'Content-Type': 'application/json'},
data=json.dumps(body, separators=(',', ':')) if body else None
)
return response.json()
def create_sign_shop(appKey, shopIdenty=None, token=None, timestamp=None, version='2.0', body=None):
params = {
'appKey': appKey,
'shopIdenty': shopIdenty,
'version': version,
'timestamp': timestamp,
}
# 排序并拼接公共参数
sorted_params = ''.join([f"{k}{params[k]}" for k in sorted(params)])
body_str = ''
if body:
body_str = json.dumps(body, separators=(',', ':'))
sign_str = f"{sorted_params}body{body_str}{token}"
else:
sign_str = f"{sorted_params}{body_str}{token}"
sign = hashlib.sha256(sign_str.encode()).hexdigest()
return sign
def call_api_shop(endpoint, appKey, shopIdenty=None, body=None):
"""调用API"""
timestamp = int(time.time() * 1000)
token = get_token(shopIdenty)
sign = create_sign_shop(appKey, shopIdenty, token, timestamp, body=body)
# 构建请求URL
url = f"{BASE_URL}{endpoint}?appKey={appKey}"
url += f"&shopIdenty={shopIdenty}"
url += f"&version=2.0×tamp={timestamp}&sign={sign}"
# 发送POST请求
response = requests.post(
url=url,
headers={'Content-Type': 'application/json'},
data=json.dumps(body, separators=(',', ':')) if body else None
)
return response.json()
def get_token(shop_id):
appKey = APP_KEY
shopIdenty = shop_id # 门店ID
version = '2.0' # 版本号
timestamp = int(time.time()) # 当前时间戳(单位:秒)
token = APP_SECRET # 令牌
# 拼接字符串
sign_string = f"appKey{appKey}shopIdenty{shopIdenty}timestamp{timestamp}version{version}{token}"
# 计算SHA256哈希值
sign = hashlib.sha256(sign_string.encode()).hexdigest()
# 构建查询字符串
params = {
'appKey': appKey,
'shopIdenty': shopIdenty,
'version': version,
'timestamp': timestamp,
'sign': sign
}
query_string = urlencode(params)
# 完整的请求URL
uri = '/open/v1/token/get'
request_url = f'{BASE_URL}{uri}?{query_string}'
# 发送GET请求
response = requests.get(request_url)
req = loads(response.text)
shop_token = req['result']['token']
return shop_token
def get_pay_info(shop_no, bill_id):
uri = '/open/standard/order/queryDetail'
body = {
"orderId": bill_id
}
pay_types = []
# 获取支付成功、退款成功的数据
try:
response = call_api_shop(uri, APP_KEY, shopIdenty=shop_no, body=body)
payments = response['result']['data']['openPaymentDetailVoList']
if len(payments) == 1:
if 'PAY_SUCCESS' in payments[0]['payDetailStatus']:
pay_types = [payments[0]['payMethodName']]
flag = 0
if 'REFUND_SUCCESS' in payments[0]['payDetailStatus']:
pay_types = [payments[0]['payMethodName']]
flag = 1
else:
for payment in payments:
if 'PAY_SUCCESS' in payment['payDetailStatus']:
pay_type = payment['payMethodName'] + ':' + str(float(payment['actualReceiveAmt']) / 100)
pay_types.append(pay_type)
elif 'REFUND_SUCCESS' in payment['payDetailStatus']:
pay_type = payment['payMethodName'] + ':' + str(-1*float(payment['actualReceiveAmt']) / 100)
pay_types.append(pay_type)
else:
continue
pay_types = [','.join(pay_types)]
flag = 0
except Exception as e:
pay_types = ['无支付方式']
flag = 0
return flag, pay_types[0]
# 消息通知
def wx_notice(message):
wx_url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=2fcb776f-5216-4381-a03a-683fdc8d4270'
data = {
"msgtype": "text",
"text": {
"content": message,
"mentioned_list": [], # 需@人的姓名
"mentioned_mobile_list": [] # 需@人的手机号
}
}
requests.post(url=wx_url, json=data)
# 金蝶单据处理
def add_bill(flag, doctpye, table, save_data):
"""
:param doctpye: 业务名称
:param table: 表名
:param save_data: json数据
:return: 单据内码、单据编号
""" # 保存
if flag == 'SZ':
api_sdk = api_sdk_sz
else:
api_sdk = api_sdk_jy
dataPara = api_sdk.Save(table, save_data)
dataPara = json.loads(dataPara)
retInfo = list(list(dataPara.values())[0].values())[0]
respcode = retInfo['IsSuccess']
if respcode:
billNo = retInfo['SuccessEntitys'][0]["Number"]
ret_info = "E0000-【{}】-单号[{}]创建成功!".format(doctpye, billNo)
# # 暂不提交和审核
# # 提交
# res_data = api_sdk.Submit(table, {"Numbers": [billNo]})
# res_data = json.loads(res_data) # info = list(list(res_data.values())[0].values())[0] # respcode = info['IsSuccess'] # if respcode: # ret_info = "E0000-【{}】-单号[{}]提交成功!".format(doctpye, billNo)
# # 审核
# res_data = api_sdk.Audit(table, {"Numbers": [billNo]})
# res_data = json.loads(res_data) # info = list(list(res_data.values())[0].values())[0] # respcode = info['IsSuccess'] # if respcode: # ret_info = "E0000-【{}】-单号[{}]已审核!".format(doctpye, billNo)
else:
respdesc = retInfo['Errors'][0]['Message']
ret_info = "E0009-同步{}失败,失败原因:{}".format(doctpye, respdesc)
if '唯一' in ret_info:
pass
else:
msg_info = '金蝶云星空:{}'.format(ret_info)
wx_notice(msg_info)
return ret_info
def get_kingdee_supply(flag, org_id, supply_name):
"""
:param org_id: :param cust_name: :return:
""" if flag == 'SZ':
api_sdk = api_sdk_sz
else:
api_sdk = api_sdk_jy
table = "BD_Supplier" # 供应商资料
data = {
"FormId": table,
"FieldKeys": "FNumber, FName",
"FilterString": [{"Left": "(", "FieldName": "FName", "Compare": "=", "Value": supply_name, "Right": ")",
"Logic": "AND"},
{"Left": "(", "FieldName": "FUseOrgId.FNumber", "Compare": "=", "Value": org_id, "Right": ")",
"Logic": ""}],
"OrderString": "",
"TopRowCount": 0,
"StartRow": 0,
"Limit": 10,
"SubSystemId": ""
}
dataPara = api_sdk.ExecuteBillQuery(data)
dataPara = json.loads(dataPara)
if len(dataPara) == 0:
supply_info = {}
else:
supply_info = {
'supply_no': dataPara[0][0],
'supply_name': dataPara[0][1],
}
return supply_info
def get_kingdee_wl(flag, org_id, wl_name):
"""
:param org_id: :param cust_name: :return:
""" if flag == 'SZ':
api_sdk = api_sdk_sz
else:
api_sdk = api_sdk_jy
table = "BD_MATERIAL" # 物料
data = {
"FormId": table,
"FieldKeys": "FNumber, FName",
"FilterString": [{"Left": "(", "FieldName": "FName", "Compare": "=", "Value": wl_name, "Right": ")",
"Logic": "AND"},
{"Left": "(", "FieldName": "FUseOrgId.FNumber", "Compare": "=", "Value": org_id, "Right": ")",
"Logic": ""}],
"OrderString": "",
"TopRowCount": 0,
"StartRow": 0,
"Limit": 10,
"SubSystemId": ""
}
dataPara = api_sdk.ExecuteBillQuery(data)
dataPara = json.loads(dataPara)
if len(dataPara) == 0:
wl_info = {}
else:
wl_info = {
'wl_no': dataPara[0][0],
'wl_name': dataPara[0][1],
}
return wl_info
def save_ysd(flag, org_id, bill_no, bill_date, cust_no, remark, details):
"""
:param bill_no: :param org_id: :param cust_no: :param bill_date: :param remark: :param details: :return:
""" post_data = {
"Model": {
"FBillTypeID": {
"FNUMBER": "YSD01_SYS"
},
"FBillNo": bill_no,
"FDATE": bill_date,
"FCUSTOMERID": {
"FNumber": cust_no # 客户代码
},
"FCURRENCYID": {
"FNumber": "PRE001"
},
"FSETTLEORGID": {
"FNumber": org_id
},
"FPAYORGID": {
"FNumber": org_id
},
"FSALEORGID": {
"FNumber": org_id
},
"F_TLWD_Assistant": {
"FNumber": cust_no
},
"F_TLWD_Text": bill_no,
"FISTAX": True,
"FCancelStatus": "A",
"FSetAccountType": "3",
"FAR_Remark": remark,
"FEntityDetail": details
}
}
# 保存单据
ret_info = add_bill(flag, "应收单", "AR_receivable", post_data)
return ret_info
# 应付单
def save_yfd(flag, org_id, bill_no, bill_date, supply_no, remark, details):
post_data = {
"Model": {
"FID": 0,
"FBillTypeID": {
"FNUMBER": "YFD01_SYS"
},
"FBillNo": bill_no,
"FISINIT": False,
"FDATE": bill_date,
"FDOCUMENTSTATUS": "Z",
"FSUPPLIERID": {
"FNumber": supply_no
},
"FCURRENCYID": {
"FNumber": "PRE001"
},
"FISPRICEEXCLUDETAX": True,
"FBUSINESSTYPE": "CG",
"FISTAX": True,
"FSETTLEORGID": {
"FNumber": org_id
},
"FPAYORGID": {
"FNumber": org_id
},
"FSetAccountType": "1",
"FISTAXINCOST": False,
"FISHookMatch": False,
"FCancelStatus": "A",
"FISBYIV": False,
"FISGENHSADJ": False,
"FISINVOICEARLIER": False,
"FWBOPENQTY": False,
"FIsGeneratePlanByCostItem": False,
"FsubHeadSuppiler": {
"FORDERID": {
"FNumber": supply_no
},
"FTRANSFERID": {
"FNumber": supply_no
},
"FChargeId": {
"FNumber": supply_no
},
},
"FEntityDetail": details
}
}
# 保存单据
ret_info = add_bill(flag, "应付单", "AP_Payable", post_data)
return ret_info
# 数据库处理
def insert_cgrk_data(curr_obj, ins_data):
"""
:param curr_obj: :param ins_data: :return:
""" bill_no = ins_data['bill_no']
bill_status = ins_data['bill_status']
shop_no = ins_data['shop_no']
shop_name = ins_data['shop_name']
org_id = ins_data['org_id']
org_name = ins_data['org_name']
supply_no = ins_data['supply_no']
supply_name = ins_data['supply_name']
bill_type= ins_data['bill_type']
buss_date= ins_data['buss_date']
purchase_date = ins_data['purchase_date']
total_amt= ins_data['total_amt']
total_amt_notax = ins_data['total_amt_notax']
remarks = ins_data['remarks']
created_time = time.strftime('%Y-%m-%d', time.localtime())
updated_time = time.strftime('%Y-%m-%d', time.localtime())
sz_data_status = 'E0000'
sz_data_status_desc = '待同步'
jy_data_status = 'E0000'
jy_data_status_desc = '待同步'
entities = (bill_no,bill_status,shop_no,shop_name,org_id, org_name, supply_no, supply_name,bill_type,buss_date,
purchase_date,total_amt,total_amt_notax,remarks,created_time,
updated_time,sz_data_status,sz_data_status_desc, jy_data_status, jy_data_status_desc)
try:
curr_obj.execute("""INSERT INTO kry_cgdd (bill_no,bill_status,shop_no,shop_name,org_id,org_name,supply_no,supply_name,bill_type,
buss_date,purchase_date,total_amt,total_amt_notax,remarks,created_time,updated_time,sz_data_status,
sz_data_status_desc, jy_data_status, jy_data_status_desc) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""", entities)
except BaseException as e:
if 'UNIQUE constraint' in str(e):
print("有重复数据:[{}] {}".format(e, bill_no))
else:
print("登记数据异常:[{}]".format(e))
return False
return True
def modify_cgdd_data(curr_obj, flag, bill_no, order_status, order_status_desc):
"""
:param curr_obj: :param order_no: :param order_status: :param order_status_desc: :return:
""" try:
if flag == 'SZ':
curr_obj.execute("UPDATE kry_cgdd SET sz_data_status=?, sz_data_status_desc=? WHERE bill_no=?",
(order_status, order_status_desc, bill_no))
else:
curr_obj.execute("UPDATE kry_cgdd SET jy_data_status=?, jy_data_status_desc=? WHERE bill_no=?",
(order_status, order_status_desc, bill_no))
except BaseException as e:
print("更新数据失败:{} ".format(e))
return False
return True
def insert_xsdd_data(curr_obj, ins_data):
"""
:param curr_obj: :param ins_data: :return:
""" shop_no = ins_data['shop_no']
shop_name = ins_data['shop_name']
org_id = ins_data['org_id']
org_name = ins_data['org_name']
cust_no = ins_data['cust_no']
order_id = ins_data['order_id']
busi_order_no = ins_data['busi_order_no']
order_status = ins_data['order_status']
order_type = ins_data['order_type']
pay_type = ins_data['pay_type']
order_amt = ins_data['order_amt']
promo_amt = ins_data['promo_amt']
order_received_amt = ins_data['order_received_amt']
open_time = ins_data['open_time']
finish_time = ins_data['finish_time']
third_order_no = ins_data['third_order_no']
serial_no = ins_data['serial_no']
third_serial_no = ins_data['third_serial_no']
created_time = time.strftime('%Y-%m-%d', time.localtime())
updated_time = time.strftime('%Y-%m-%d', time.localtime())
if pay_type == '无支付方式':
sz_data_status = 'E0003'
sz_data_status_desc = '不同步'
jy_data_status = 'E00003'
jy_data_status_desc = '不同步'
else:
sz_data_status = 'E0000'
sz_data_status_desc = '待同步'
jy_data_status = 'E0000'
jy_data_status_desc = '待同步'
entities = (shop_no,shop_name,org_id,org_name,cust_no,order_id,busi_order_no,
order_status,order_type,pay_type, order_amt,promo_amt,order_received_amt,
open_time,finish_time,third_order_no,serial_no,third_serial_no,created_time,updated_time,
sz_data_status, sz_data_status_desc,
jy_data_status, jy_data_status_desc)
try:
curr_obj.execute("""INSERT INTO kry_xsdd (shop_no,shop_name,org_id,org_name,cust_no,order_id,busi_order_no,order_status,
order_type,pay_type, order_amt,promo_amt,order_received_amt,open_time,finish_time, third_order_no,serial_no,third_serial_no,created_time,updated_time, sz_data_status, sz_data_status_desc, jy_data_status, jy_data_status_desc) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""", entities)
except BaseException as e:
if 'UNIQUE constraint' in str(e):
print("有重复数据:[{}] {}".format(e, order_id))
else:
print("登记数据异常:[{}]".format(e))
return False
return True
def modify_xsdd_data(curr_obj, flag, bill_no, order_status, order_status_desc):
"""
:param curr_obj: :param order_no: :param order_status: :param order_status_desc: :return:
""" try:
if flag == 'SZ':
curr_obj.execute("UPDATE kry_xsdd SET sz_data_status=?, sz_data_status_desc=? WHERE busi_order_no=?",
(order_status, order_status_desc, bill_no))
else:
curr_obj.execute("UPDATE kry_xsdd SET jy_data_status=?, jy_data_status_desc=? WHERE busi_order_no=?",
(order_status, order_status_desc, bill_no))
except BaseException as e:
print("更新数据失败:{} ".format(e))
return False
return True
def get_shop_info(shop_no):
conn = sqlite3.connect(DB_FILE)
curr = conn.cursor()
query = """ SELECT shop_name, kingdee_org_code, kingdee_org_name FROM shop_para WHERE shop_id = ? """
val = (shop_no,)
curr.execute(query, val)
# 获取查询结果
rows = curr.fetchall()
shop_info = {"shop_name": rows[0][0], "org_id": rows[0][1], "org_name": rows[0][2]}
curr.close()
conn.close()
return shop_info
# 采购入库查询
def get_cgrk_data(shop_no, start_date, end_date):
shop = get_shop_info(shop_no)
shop_name = shop['shop_name']
org_id = shop['org_id']
org_name = shop['org_name']
## 获取总记录数
body = {
"orgType": 2,
"orgId": shop_no,
"page": 1,
"rows": 100,
"billType": 912,
"billStatusList": [
962
],
"updateTimeStart": start_date,
"updateTimeEnd": end_date,
}
uri = '/open/standard/procurement/supply/purchase/open/standard/purchase/in/list'
response = call_api(uri, APP_KEY, brandId=BRAN_ID, body=body)
res_code = response['result']['serverCode']
res_msg = response['result']['messageId']
if res_code != 10000:
msg = f'【客如云[{shop_name}]】:[{start_date}~{end_date}]没有采购入库数据!'
wx_notice(msg)
return
total = response['result']['data']['total']
total_row = math.ceil(total/100)
conn = sqlite3.connect(DB_FILE)
curr_obj = conn.cursor()
# 循环读取数据
page = 1
while page < total_row:
body = {
"orgType": 2,
"orgId": shop_no,
"bizDateStart": start_date,
"bizDateEnd": end_date,
"page": page,
"rows": 100,
"billType": 912,
"billStatusList": [
962
]
}
# 调用API
response = call_api(uri, APP_KEY, brandId=BRAN_ID, body=body)
res_code = response['result']['serverCode']
res_msg = response['result']['messageId']
total = response['result']['data']['total']
total_row = math.ceil(total/100)
if res_code != 10000:
break
page += 1
lists = response['result']['data']['list']
if len(lists) == 0:
break
for list in lists:
bill_no = list['billNo']
bill_status = list['billStatus']
supply_name = list['supplyName']
bill_type = list['billType']
buss_date = list['bussDate']
purchase_date = list['purchaseDate']
total_amt = list['totalAmt']
total_amt_notax = list['totalAmtNotax']
remarks = list['remarks']
ins_data = {
'bill_no': bill_no,
'bill_status': bill_status,
"shop_no": shop_no, # 门店ID
"shop_name": shop_name, # 门店名称
"org_id": org_id, # 组织ID
"org_name": org_name, # 组织名称
"supply_no": '',
'supply_name': supply_name,
'bill_type': bill_type,
'buss_date': buss_date,
'purchase_date': purchase_date,
'total_amt': total_amt,
'total_amt_notax': total_amt_notax,
'remarks': remarks,
}
# 插入数据到数据库
insert_cgrk_data(curr_obj, ins_data)
conn.commit()
conn.commit()
curr_obj.close()
conn.close()
# 通知客户企业微信群
msg = f'【客如云[{shop_name}]】:[{start_date}~{end_date}]采购入库获取完成!'
wx_notice(msg)
def tokd_cgdd_sync(flag, shop_no, start_date, end_date):
"""
:return:
""" conn = sqlite3.connect(DB_FILE)
curr = conn.cursor()
if flag == 'SZ':
query = """ select org_id, bill_no, supply_name, buss_date, total_amt, remarks from kry_cgdd
where shop_no=? and buss_date>=? and buss_date<=? and sz_data_status in ('E0000', 'E0009') """
else:
query = """ select org_id, bill_no, supply_name, buss_date, total_amt, remarks from kry_cgdd
where shop_no=? and buss_date>=? and buss_date<=? and jy_data_status in ('E0000', 'E0009') """
val = (shop_no, start_date, end_date,)
curr.execute(query, val)
# 获取查询结果
rows = curr.fetchall()
# 打印查询结果
cnt = 0
if 0 == len(rows):
wx_notice(f"客如云[{shop}]->金蝶[{flag}]账套:应付处理[{start_date}至{end_date}]-未查询到需要同步的异常数据!!")
curr.close()
conn.close()
return
for row in rows:
org_id = row[0]
bill_no = row[1]
supply_name = row[2]
bill_date = row[3]
total_amt = row[4]
remarks = row[5]
try:
supply_info = get_kingdee_supply(flag, org_id, supply_name)
supply_no = supply_info['supply_no']
except BaseException as e:
supply_no = ""
details = []
detail = {
"FMATERIALID": {
"FNumber": "kry-yf001"
},
"FCOSTID": {
"FNumber": "FYXM46_SYS"
},
"FPRICEUNITID": {
"FNumber": "Pcs"
},
"FPriceQty": 1.0,
"FTaxPrice": total_amt,
"FEntryTaxRate": 0,
'FINCLUDECOST': False,
"FComment": remarks,
"FTAILDIFFFLAG": False,
}
details.append(detail)
try:
res_info = save_yfd(flag, org_id, bill_no, bill_date, supply_no, "", details)
if 'E0000' in res_info:
modify_cgdd_data(curr, flag, bill_no, "E0001", '同步成功')
elif 'E0009' in res_info:
if '唯一' in res_info:
modify_cgdd_data(curr, flag, bill_no, "E0002", '同步成功[已同步过')
else:
modify_cgdd_data(curr, flag, bill_no, "E0009", res_info)
wx_notice(f"客如云[{shop_no}]->金蝶[{flag}]账套:应付处理-数据同步失败[{res_info}]!")
except BaseException as e:
res_info = "订单【{}】, 同步失败:{}".format(bill_no, e)
modify_cgdd_data(curr, flag, bill_no, "E0009", res_info)
wx_notice(f"客如云[{shop_no}]->金蝶[{flag}]账套:应付处理-数据同步失败[{res_info}]!")
cnt += 1
# 关闭游标和连接
conn.commit()
curr.close()
conn.close()
wx_notice(f"客如云[{shop_no}]->金蝶[{flag}]账套:应付处理[{start_date}至{end_date}]-同步完成,记录数[{cnt}]!!")
# 消费订单查询
def get_xsdd_data(shop_no, start_date, end_date):
# 查询店铺名称,对应金蝶组织
shop = get_shop_info(shop_no)
shop_name = shop['shop_name']
org_id = shop['org_id']
org_name = shop['org_name']
body = {
"dateType": "FINISH_TIME",
"startDate": start_date,
"endDate": end_date,
"orderStatusList": [
"SETTLED",
"SUCCESS"
],
"pageBean": {
"pageNum": 1,
"pageSize": 1
},
}
uri = '/open/standard/order/queryList'
response = call_api_shop(uri, APP_KEY, shopIdenty=shop_no, body=body)
res_code = response['result']['success']
if not res_code:
msg = f'【客如云[{shop_name}]】:[{start_date}~{end_date}]没有消费订单数据!'
wx_notice(msg)
return
total_page = int(response['result']['data']['totalPage'])
conn = sqlite3.connect(DB_FILE)
curr_obj = conn.cursor()
page = 1
while page < total_page:
body = {
"dateType": "FINISH_TIME",
"startDate": start_date,
"endDate": end_date,
"orderStatusList": [
"SETTLED",
"SUCCESS"
],
"pageBean": {
"pageNum": page,
"pageSize": 100
},
}
response = call_api_shop(uri, APP_KEY, shopIdenty=shop_no, body=body)
res_code = response['result']['success']
if not res_code:
break
page += 1
lists = response['result']['data']['list']
if len(lists) == 0:
break
for list in lists:
order_id = list['orderId']
busi_order_no = list['busiOrderNo']
order_types = {
"FOR_HERE": "堂食",
"TAKE_OUT": "外带",
"PLATFORM_TAKE_OUT": "平台外卖",
"SELF_TAKE_OUT": "自营外卖",
"OPEN_PLATFORM_TAKE_OUT": "开放平台外卖",
"SELF_TAKE": "自提",
"NO_ORDER_CASHIER": "无单收银",
"MEMBER_STORE": "会员充值",
"MEMBER_CARD_SALE": "会员售卡并储值",
"MEMBER_MANUAL_STORE": "会员补录",
"REPAYMENT_ORDER": "销账订单",
"PRIVATE_PAY_MEMBER_SALE": "权益卡售卡订单",
"COUPON_PACKAGE_SALE": "券包售卖订单",
"ONLINE_PAY_BILL": "在线买单",
"STATIC_CODE": "客如云收款码",
"DEPOSIT": "订金订单",
"EARNEST_MONEY": "定金订单",
"CASH_PLEDGE": "押金订单",
"GIFT_CARD_SALE": "礼品卡订单",
"GIFT_PACKAGE_SALE": "礼包订单",
"GIFT_CARD_STORE": "礼品卡储值订单",
"GROUP_PURCHASING": "拼团订单",
"POINTS_MALL": "积分商城订单",
"BARGAIN": "砍价订单",
"SEC_KILL": "秒杀订单",
"COUPON_SALE": "团购券售卖"
}
order_status = {
"WAIT_PROCESSED": "待处理",
"WAIT_SETTLED": "待结账",
"SETTLED": "已结账",
"REFUND": "已退单",
"INVALID": "已作废",
"CANCELLED": "已取消",
"REJECTED": "已拒绝",
"SUCCESS": "已完成"
}
order_status_desc = order_status.get(list['orderStatus'])
order_status = list['orderStatus'] + '-' + order_status_desc
order_type = order_types.get(list['orderType'])
try:
if "会员充值" in order_type:
org_id = '103'
except:
print(f"orderType=[{list['orderType']}]")
payment_flag, pay_type = get_pay_info(shop_no, order_id)
if payment_flag:
order_amt = -1*float(list['orderAmt'])/100
promo_amt = -1*float(list['promoAmt'])/100
try:
order_received_amt = -1*float(list['orderReceivedAmt'])/100
third_order_no = ''
except:
msg = f"【客如云[{shop_name}]】:[orderReceivedAmt={list['orderReceivedAmt']}]订单数据异常!"
third_order_no = msg
wx_notice(msg)
order_received_amt = 0
else:
order_amt = float(list['orderAmt']) / 100
promo_amt = float(list['promoAmt']) / 100
try:
order_received_amt = float(list['orderReceivedAmt']) / 100
third_order_no = ''
except:
msg = f"【客如云[{shop_name}]】:[orderReceivedAmt={list['orderReceivedAmt']}]订单数据异常!"
third_order_no = msg
wx_notice(msg)
order_received_amt = 0
open_time = list['openTime']
finish_time = list['finishTime']
# third_order_no = list['thirdOrderNo']
serial_no = list['serialNo']
third_serial_no = list['thirdSerialNo']
ins_data = {
"shop_no": shop_no, # 门店ID
"shop_name": shop_name, # 门店名称
"org_id": org_id, # 组织ID
"org_name": org_name, # 组织名称
"cust_no": "KRY-0001", # 客如云
"order_id": order_id, # 订单ID
"busi_order_no": busi_order_no, # 业务订单号
"order_status": order_status, # 订单状态
"order_type": order_type, # 订单类型
"pay_type": pay_type, # 支付方式
"order_amt": order_amt, # 订单金额(单位/分)
"promo_amt": promo_amt, # 优惠金额(单位/分)
"order_received_amt": order_received_amt, # 订单收入/订单实收(单位/分)
"open_time": open_time, # 下单时间
"finish_time": finish_time, # 完结时间
"third_order_no": third_order_no, # 第三方订单号
"serial_no": serial_no, # 订单流水号
"third_serial_no": "" # 第三方流水号
}
# 插入数据到数据库
insert_xsdd_data(curr_obj, ins_data)
conn.commit()
curr_obj.close()
conn.close()
# # 通知客户企业微信群
msg = msg = f'【客如云[{shop_name}]】:[{start_date}~{end_date}]订单数据获取完成!'
wx_notice(msg)
## 同步金蝶处理
def tokd_xsdd_sync(flag, shop_no, start_date, end_date):
"""
:return:
""" conn = sqlite3.connect(DB_FILE)
curr = conn.cursor()
if flag == 'SZ':
query = """ select org_id, cust_no, finish_time, busi_order_no, order_type, pay_type, order_received_amt
from kry_xsdd where shop_no=? and SUBSTR(finish_time,1,10)>=? and SUBSTR(finish_time,1,10)<=?
and sz_data_status in ('E0000', 'E0009') """
else:
query = """ select org_id, cust_no, finish_time, busi_order_no, order_type, pay_type, order_received_amt
from kry_xsdd where shop_no=? and SUBSTR(finish_time,1,10)>=? and SUBSTR(finish_time,1,10)<=?
and jy_data_status in ('E0000', 'E0009') """
val = (shop_no, start_date, end_date,)
curr.execute(query, val)
# 获取查询结果
rows = curr.fetchall()
# 打印查询结果
cnt = 0
if 0 == len(rows):
wx_notice(f"客如云[{shop}]->金蝶[{flag}]账套:应收处理[{start_date}至{end_date}]-未查询到需要同步的异常数据!!")
curr.close()
conn.close()
return
for row in rows:
org_id = row[0]
cust_no = row[1]
bill_date = row[2]
bill_no = row[3]
order_type = row[4]
pay_type = row[5]
ys_amt = row[6]
details = []
if ',' in pay_type:
pay_types = pay_type.split(',')
for pay_info in pay_types:
pay_type = pay_info.split(':')[0]
ys_amt = float(pay_info.split(':')[1])
if ys_amt < 0:
qty = -1
ys_amt = abs(ys_amt)
else:
qty = 1
try:
wl_info = get_kingdee_wl(flag, org_id, pay_type)
wl_code = wl_info['wl_no']
except:
wl_code = ""
detail = {
"FMATERIALID": {
"FNumber": wl_code
},
"FTaxPrice": ys_amt,
# "FEntryTaxRate": 13,
"FPriceQty": qty,
"FComment": "",
}
details.append(detail)
else:
if ":" in pay_type:
pay_type = pay_type.split(':')[0]
try:
wl_info = get_kingdee_wl(flag, org_id, pay_type)
wl_code = wl_info['wl_no']
except:
wl_code = ""
if ys_amt < 0:
qty = -1
else:
qty = 1
detail = {
"FMATERIALID": {
"FNumber": wl_code
},
"FTaxPrice": ys_amt,
# "FEntryTaxRate": 13,
"FPriceQty": qty,
"FComment": "",
}
details.append(detail)
try:
res_info = save_ysd(flag, org_id, bill_no, bill_date, cust_no, order_type, details)
if 'E0000' in res_info:
modify_xsdd_data(curr, flag, bill_no, "E0001", '同步成功')
elif 'E0009' in res_info:
if '唯一' in res_info:
modify_xsdd_data(curr, flag, bill_no, "E0002", '同步成功[已同步过]')
else:
modify_xsdd_data(curr, flag, bill_no, "E0009", res_info)
wx_notice(f"客如云[{shop_no}]->金蝶[{flag}]账套:应收处理-数据同步失败[{res_info}]!")
except BaseException as e:
res_info = "订单【{}】, 同步失败:{}".format(bill_no, e)
modify_xsdd_data(curr, flag, bill_no, "E0009", res_info)
wx_notice(f"客如云[{shop_no}]->金蝶[{flag}]账套:应收处理-数据同步失败[{res_info}]!")
cnt += 1
# 关闭游标和连接
conn.commit()
curr.close()
conn.close()
wx_notice(f"客如云[{shop_no}]->金蝶[{flag}]账套:应收处理[{start_date}至{end_date}]-同步完成,记录数[{cnt}]!!")
def get_shoplist():
uri = '/open/standard/shop/MerchantOrgReadService.queryBrandStores'
# 调用API
response = call_api(uri, APP_KEY, brandId=34812143, body=None)
# 打印响应内容
shops = response['result']['shops']
for shop in shops:
print(shop['shopId'], shop['name'])
if __name__ == '__main__':
# 业务数据
# get_shoplist()
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
| shop_id | shop_name | kd_code | kd_name | --------------------------------------------------------------------------------------- 35170196 名古屋日料烤肉(新翼广场店) 103.04 佛山市起翼餐饮服务有限公司顺德第一分公司
35114097 啡同凡享(新翼广场店) 103.07 佛山市起翼餐饮服务有限公司顺德第四分公司
35082103 喜翼楼(赤坎店) 106 湛江市喜翼楼餐饮服务有限公司
35172137 喜翼港式茶餐厅(新翼广场店) 103 佛山市起翼餐饮服务有限公司
34994157 喜翼港式茶餐厅(豪庭店) 103.02 佛山市起翼餐饮服务有限公司湛江豪庭分公司
34830154 喜翼港式茶餐厅(鼎盛店) 103.01 佛山市起翼餐饮服务有限公司湛江鼎盛分公司
35142115 对面粥粉面(新翼广场店) 103.06 佛山市起翼餐饮服务有限公司顺德第三分公司
--------------------------------------------------------------------------------------- """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" # shops = [34830154]
# 采购数据同步测试
shops = [35170196, 35114097, 35082103, 35172137, 34994157, 34830154, 35142115]
# for shop in shops:
# get_cgrk_data(shop, '2025-01-01 00:00:00', '2025-01-22 00:00:00') # tokd_cgdd_sync('SZ', shop, '2025-01-01', '2025-01-22') # tokd_cgdd_sync('JY', shop, '2025-01-01', '2025-01-21')
# sync_dates = ["2025-01-01", "2025-01-02", "2025-01-03", "2025-01-04", "2025-01-05", # "2025-01-06", "2025-01-07", "2025-01-08", "2025-01-09", "2025-01-10", # "2025-01-11", "2025-01-12", "2025-01-13", "2025-01-14", "2025-01-15", "2025-01-16", # "2025-01-17","2025-01-18","2025-01-19", "2025-01-20", "2025-01-21"] # sync_dates = ["2025-01-22"]
for sync_date in sync_dates:
s_date = sync_date + " 00:00:00"
e_date = sync_date + " 23:59:59"
# for shop in shops:
# # get_cgrk_data(shop, s_date, e_date) # # tokd_cgdd_sync('SZ', shop, sync_date, sync_date) # # tokd_cgdd_sync('JY', shop, sync_date, sync_date)
# 销售数据同步测试
for shop in shops:
get_xsdd_data(shop, s_date, e_date)
# tokd_xsdd_sync('SZ', shop, sync_date, sync_date)
# tokd_xsdd_sync('JY', shop, sync_date, sync_date)