diff --git a/wwwroot/add_provider_recharge.dspy b/wwwroot/add_provider_recharge.dspy new file mode 100644 index 0000000..ad33af6 --- /dev/null +++ b/wwwroot/add_provider_recharge.dspy @@ -0,0 +1,60 @@ + +ns = params_kw.copy() +supplier_id = ns.get('supplier_id', '') +amount = ns.get('amount', 0) +payment_method = ns.get('payment_method', '') +transaction_no = ns.get('transaction_no', '') +remark = ns.get('remark', '') + +if not supplier_id: + return json.dumps({'success': False, 'error': '请选择供应商'}, ensure_ascii=False) +if not amount or float(amount) <= 0: + return json.dumps({'success': False, 'error': '充值金额必须大于0'}, ensure_ascii=False) + +acc_dbname = get_module_dbname('accounting') +userorgid = await get_userorgid() +acc_id = getID() +bill_id = getID() + +# 创建充值记录到accounting_log +log_data = { + 'id': acc_id, + 'accountid': supplier_id, + 'acc_date': curDateString(), + 'acc_dir': 'C', + 'amount': float(amount), + 'summary': f'供应商充值 - {payment_method} {transaction_no}', + 'business_op': '供应商充值', + 'billid': bill_id, + 'created_at': timestampstr() +} + +# 创建bill记录 +bill_data = { + 'id': bill_id, + 'customerid': supplier_id, + 'resellerid': userorgid, + 'business_op': '供应商充值', + 'amount': float(amount), + 'bill_date': curDateString(), + 'bill_timestamp': timestampstr(), + 'bill_state': '1' +} + +db = DBPools() +try: + async with db.sqlorContext(acc_dbname) as sor: + await sor.C('bill', bill_data) + await sor.C('accounting_log', log_data) + + debug(f'provider_recharge: created {acc_id}, supplier={supplier_id}, amt={amount}') + return json.dumps({ + 'success': True, + 'message': f'充值记录已创建,金额: {amount}', + 'id': acc_id, + 'bill_id': bill_id + }, ensure_ascii=False, default=str) + +except Exception as e: + debug(f'provider_recharge error: {format_exc()}') + return json.dumps({'success': False, 'error': f'充值失败: {str(e)}'}, ensure_ascii=False) diff --git a/wwwroot/add_provider_settlement.dspy b/wwwroot/add_provider_settlement.dspy new file mode 100644 index 0000000..210db28 --- /dev/null +++ b/wwwroot/add_provider_settlement.dspy @@ -0,0 +1,70 @@ + +ns = params_kw.copy() +record_id = ns.get('id', '') +remark = ns.get('remark', '') +payment_method = ns.get('payment_method', '') + +if not record_id: + return json.dumps({'success': False, 'error': '缺少记录ID'}, ensure_ascii=False) + +sc_dbname = get_module_dbname('supplychain') +acc_dbname = get_module_dbname('accounting') +userorgid = await get_userorgid() + +# 查询supplychain_accounting记录 +db = DBPools() +async with db.sqlorContext(sc_dbname) as sor: + recs = await sor.sqlExe(""" + SELECT sa.*, sp.supplier_name + FROM supplychain_accounting sa + LEFT JOIN suppliers sp ON sa.supplier_id = sp.id COLLATE utf8mb4_unicode_ci + WHERE sa.id = ${record_id}$ + """, {'record_id': record_id}) + +if not recs: + return json.dumps({'success': False, 'error': '记录不存在'}, ensure_ascii=False) + +rec = recs[0] + +# 供应商结算: supply_amount是我方应付给供应商的金额 +from accounting.settle import SettleAccounting +settle_log = { + 'accounting_orgid': userorgid, + 'providerid': rec.supplier_id or '', + 'sale_mode': '1', + 'settle_date': str(rec.sale_date or curDateString()), + 'settle_amt': float(rec.supply_amount or 0), + 'business_op': '供应商结算', + 'remark': remark +} + +try: + async with db.sqlorContext(acc_dbname) as acc_sor: + sa = SettleAccounting(settle_log) + await sa.accounting(acc_sor) + + # 更新sales_ledger + async with db.sqlorContext(sc_dbname) as sc_sor: + await sc_sor.sqlExe(""" + UPDATE sales_ledger + SET settlement_status = '1', updated_at = NOW() + WHERE productid = ${productid}$ + AND supplier_id = ${supplier_id}$ + AND sale_date = ${sale_date}$ + """, { + 'productid': rec.productid, + 'supplier_id': rec.supplier_id, + 'sale_date': str(rec.sale_date) + }) + + debug(f'provider_settlement: settled {record_id}, amt={rec.supply_amount}') + return json.dumps({ + 'success': True, + 'message': f'结算成功,金额: {rec.supply_amount}', + 'settle_id': sa.settleid, + 'bill_id': sa.billid + }, ensure_ascii=False, default=str) + +except Exception as e: + debug(f'provider_settlement error: {format_exc()}') + return json.dumps({'success': False, 'error': f'结算失败: {str(e)}'}, ensure_ascii=False) diff --git a/wwwroot/get_provider_recharge.dspy b/wwwroot/get_provider_recharge.dspy new file mode 100644 index 0000000..e9e4441 --- /dev/null +++ b/wwwroot/get_provider_recharge.dspy @@ -0,0 +1,86 @@ + +ns = params_kw.copy() +ns['page'] = ns.get('page') or 1 +ns['sort'] = ns.get('sort') or 'acc_date' + +date_start = ns.get('date_start', '') +date_end = ns.get('date_end', '') +supplier_id = ns.get('supplier_id', '') +recharge_status = ns.get('recharge_status', '') + +acc_dbname = get_module_dbname('accounting') +sc_dbname = get_module_dbname('supplychain') +userorgid = await get_userorgid() + +# 查询供应商充值记录: accounting_log中business_op='供应商充值'的记录 +where = "WHERE al.business_op = '供应商充值'" +sql_params = {} + +if date_start: + where += " AND al.acc_date >= ${date_start}$" + sql_params['date_start'] = date_start +if date_end: + where += " AND al.acc_date <= ${date_end}$" + sql_params['date_end'] = date_end + +sql = f""" +SELECT + al.id, + al.accountid, + al.acc_date as recharge_date, + al.amount, + al.acc_dir, + al.summary, + al.business_op, + al.billid, + b.customerid as supplier_id, + sp.supplier_name as supplier_id_text, + CASE + WHEN al.billid IS NOT NULL AND al.billid != '' THEN '2' + WHEN al.amount > 0 THEN '1' + ELSE '0' + END as recharge_status, + al.created_at +FROM accounting_log al +LEFT JOIN bill b ON al.billid = b.id COLLATE utf8mb4_unicode_ci +LEFT JOIN ( + SELECT id, supplier_name FROM suppliers +) sp ON b.customerid = sp.id COLLATE utf8mb4_unicode_ci +{where} +ORDER BY al.acc_date DESC, al.id +""" + +if supplier_id: + sql = f"SELECT * FROM ({sql}) t WHERE t.supplier_id = ${supplier_id}$" + sql_params['supplier_id'] = supplier_id +if recharge_status: + sql = f"SELECT * FROM ({sql}) t WHERE t.recharge_status = ${recharge_status}$" + sql_params['recharge_status'] = recharge_status + +db = DBPools() +async with db.sqlorContext(acc_dbname) as sor: + recs = await sor.sqlExe(sql, sql_params) + +rows = [] +for r in (recs or []): + rows.append({ + 'id': r.id, + 'supplier_id': r.supplier_id or '', + 'supplier_id_text': r.supplier_id_text or '', + 'recharge_date': str(r.recharge_date or ''), + 'amount': float(r.amount or 0), + 'payment_method': r.summary or '', + 'transaction_no': r.billid or '', + 'recharge_status': r.recharge_status or '0', + 'remark': r.summary or '', + 'created_at': str(r.created_at or '') + }) + +total = len(rows) +debug(f'get_provider_recharge: {total} records') + +return json.dumps({ + 'success': True, + 'total': total, + 'rows': rows +}, ensure_ascii=False, default=str) diff --git a/wwwroot/get_provider_settlement.dspy b/wwwroot/get_provider_settlement.dspy new file mode 100644 index 0000000..2e642c8 --- /dev/null +++ b/wwwroot/get_provider_settlement.dspy @@ -0,0 +1,86 @@ + +ns = params_kw.copy() +ns['page'] = ns.get('page') or 1 +ns['sort'] = ns.get('sort') or 'sale_date' + +date_start = ns.get('date_start', '') +date_end = ns.get('date_end', '') +supplier_id = ns.get('supplier_id', '') +settlement_status = ns.get('settlement_status', '') + +sc_dbname = get_module_dbname('supplychain') +userorgid = await get_userorgid() + +where = "WHERE sa.resellerid = ${userorgid}$" +sql_params = {'userorgid': userorgid} + +if date_start: + where += " AND sa.sale_date >= ${date_start}$" + sql_params['date_start'] = date_start +if date_end: + where += " AND sa.sale_date <= ${date_end}$" + sql_params['date_end'] = date_end +if supplier_id: + where += " AND sa.supplier_id = ${supplier_id}$" + sql_params['supplier_id'] = supplier_id + +sql = f""" +SELECT + sa.id, + sa.supplier_id, + sp.supplier_name as supplier_id_text, + sa.sale_date, + sa.sale_date as settlement_period, + p.name as product_name, + sa.productid, + sa.quantity, + sa.supply_amount as amount, + sa.dist_amount, + COALESCE(sl.settlement_status, '0') as settlement_status, + sa.source_type, + sa.source_id +FROM supplychain_accounting sa +LEFT JOIN product p ON sa.productid = p.id COLLATE utf8mb4_unicode_ci +LEFT JOIN suppliers sp ON sa.supplier_id = sp.id COLLATE utf8mb4_unicode_ci +LEFT JOIN sales_ledger sl ON sl.productid = sa.productid COLLATE utf8mb4_unicode_ci + AND sl.supplier_id = sa.supplier_id COLLATE utf8mb4_unicode_ci + AND sl.sale_date = sa.sale_date +{where} +ORDER BY sa.sale_date DESC, sa.id +""" + +if settlement_status: + sql = f""" +SELECT * FROM ({sql}) t WHERE t.settlement_status = ${settlement_status}$ +""" + sql_params['settlement_status'] = settlement_status + +db = DBPools() +async with db.sqlorContext(sc_dbname) as sor: + recs = await sor.sqlExe(sql, sql_params) + +rows = [] +for r in (recs or []): + rows.append({ + 'id': r.id, + 'supplier_id': r.supplier_id or '', + 'supplier_id_text': r.supplier_id_text or '', + 'settlement_period': str(r.sale_date or ''), + 'product_name': r.product_name or '', + 'amount': float(r.amount or 0), + 'settlement_status': r.settlement_status or '0', + 'settlement_date': '', + 'payment_method': '', + 'reference_no': r.source_id or '', + 'remark': r.source_type or '', + 'created_at': str(r.sale_date or '') + }) + +total = len(rows) +debug(f'get_provider_settlement: {total} records') + +return json.dumps({ + 'success': True, + 'total': total, + 'rows': rows +}, ensure_ascii=False, default=str) diff --git a/wwwroot/get_reseller_settlement.dspy b/wwwroot/get_reseller_settlement.dspy new file mode 100644 index 0000000..3cf956f --- /dev/null +++ b/wwwroot/get_reseller_settlement.dspy @@ -0,0 +1,87 @@ + +ns = params_kw.copy() +ns['page'] = ns.get('page') or 1 +ns['sort'] = ns.get('sort') or 'sale_date' + +date_start = ns.get('date_start', '') +date_end = ns.get('date_end', '') +sub_reseller_id = ns.get('sub_reseller_id', '') +settlement_status = ns.get('settlement_status', '') + +sc_dbname = get_module_dbname('supplychain') +userorgid = await get_userorgid() + +# 查询supplychain_accounting中该分销商的记录, 关联sales_ledger结算状态 +where = "WHERE sa.resellerid = ${userorgid}$" +sql_params = {'userorgid': userorgid} + +if date_start: + where += " AND sa.sale_date >= ${date_start}$" + sql_params['date_start'] = date_start +if date_end: + where += " AND sa.sale_date <= ${date_end}$" + sql_params['date_end'] = date_end +if sub_reseller_id: + where += " AND sa.sub_distributor_id = ${sub_reseller_id}$" + sql_params['sub_reseller_id'] = sub_reseller_id + +sql = f""" +SELECT + sa.id, + sa.sub_distributor_id, + sr.sub_reseller_name as sub_reseller_id_text, + sa.sale_date, + sa.sale_date as settlement_period, + p.name as product_name, + sa.productid, + sa.quantity, + sa.dist_amount as amount, + sa.supply_amount, + COALESCE(sl.settlement_status, '0') as settlement_status, + sa.source_type, + sa.source_id +FROM supplychain_accounting sa +LEFT JOIN product p ON sa.productid = p.id COLLATE utf8mb4_unicode_ci +LEFT JOIN sub_resellers sr ON sa.sub_distributor_id = sr.id COLLATE utf8mb4_unicode_ci +LEFT JOIN sales_ledger sl ON sl.productid = sa.productid COLLATE utf8mb4_unicode_ci + AND sl.sub_reseller_id = sa.sub_distributor_id COLLATE utf8mb4_unicode_ci + AND sl.sale_date = sa.sale_date +{where} +ORDER BY sa.sale_date DESC, sa.id +""" + +if settlement_status: + sql = f""" +SELECT * FROM ({sql}) t WHERE t.settlement_status = ${settlement_status}$ +""" + sql_params['settlement_status'] = settlement_status + +db = DBPools() +async with db.sqlorContext(sc_dbname) as sor: + recs = await sor.sqlExe(sql, sql_params) + +rows = [] +for r in (recs or []): + rows.append({ + 'id': r.id, + 'sub_reseller_id': r.sub_distributor_id or '', + 'sub_reseller_id_text': r.sub_reseller_id_text or '', + 'settlement_period': str(r.sale_date or ''), + 'product_name': r.product_name or '', + 'amount': float(r.amount or 0), + 'settlement_status': r.settlement_status or '0', + 'settlement_date': '', + 'payment_method': '', + 'reference_no': r.source_id or '', + 'remark': r.source_type or '', + 'created_at': str(r.sale_date or '') + }) + +total = len(rows) +debug(f'get_reseller_settlement: {total} records') + +return json.dumps({ + 'success': True, + 'total': total, + 'rows': rows +}, ensure_ascii=False, default=str) diff --git a/wwwroot/update_provider_recharge.dspy b/wwwroot/update_provider_recharge.dspy new file mode 100644 index 0000000..bbc5e59 --- /dev/null +++ b/wwwroot/update_provider_recharge.dspy @@ -0,0 +1,25 @@ + +ns = params_kw.copy() +record_id = ns.get('id', '') +remark = ns.get('remark', '') + +if not record_id: + return json.dumps({'success': False, 'error': '缺少记录ID'}, ensure_ascii=False) + +acc_dbname = get_module_dbname('accounting') + +db = DBPools() +try: + async with db.sqlorContext(acc_dbname) as sor: + # 更新accounting_log的备注 + await sor.U('accounting_log', { + 'id': record_id, + 'summary': remark + }) + + debug(f'update_provider_recharge: updated {record_id}') + return json.dumps({'success': True, 'message': '充值记录已更新'}, ensure_ascii=False) + +except Exception as e: + debug(f'update_provider_recharge error: {format_exc()}') + return json.dumps({'success': False, 'error': f'更新失败: {str(e)}'}, ensure_ascii=False) diff --git a/wwwroot/update_provider_settlement.dspy b/wwwroot/update_provider_settlement.dspy new file mode 100644 index 0000000..f391af0 --- /dev/null +++ b/wwwroot/update_provider_settlement.dspy @@ -0,0 +1,41 @@ + +# 供应商结算确认(同add_provider_settlement逻辑,update用于确认操作) +ns = params_kw.copy() +record_id = ns.get('id', '') +remark = ns.get('remark', '') + +if not record_id: + return json.dumps({'success': False, 'error': '缺少记录ID'}, ensure_ascii=False) + +sc_dbname = get_module_dbname('supplychain') +userorgid = await get_userorgid() + +db = DBPools() +async with db.sqlorContext(sc_dbname) as sor: + recs = await sor.sqlExe(""" + SELECT sa.* FROM supplychain_accounting sa + WHERE sa.id = ${record_id}$ + """, {'record_id': record_id}) + +if not recs: + return json.dumps({'success': False, 'error': '记录不存在'}, ensure_ascii=False) + +rec = recs[0] + +# 更新结算状态 +async with db.sqlorContext(sc_dbname) as sc_sor: + await sc_sor.sqlExe(""" + UPDATE sales_ledger + SET settlement_status = '1', updated_at = NOW(), remark = ${remark}$ + WHERE productid = ${productid}$ + AND supplier_id = ${supplier_id}$ + AND sale_date = ${sale_date}$ + """, { + 'productid': rec.productid, + 'supplier_id': rec.supplier_id, + 'sale_date': str(rec.sale_date), + 'remark': remark + }) + +debug(f'update_provider_settlement: confirmed {record_id}') +return json.dumps({'success': True, 'message': '结算已确认'}, ensure_ascii=False) diff --git a/wwwroot/update_reseller_settlement.dspy b/wwwroot/update_reseller_settlement.dspy new file mode 100644 index 0000000..7cb2e43 --- /dev/null +++ b/wwwroot/update_reseller_settlement.dspy @@ -0,0 +1,78 @@ + +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) +from accounting.settle import SettleAccounting, get_subjectid +from accounting.accounting_config import AccountingOrgs + +ns = params_kw.copy() +record_id = ns.get('id', '') +remark = ns.get('remark', '') +payment_method = ns.get('payment_method', '') + +if not record_id: + return json.dumps({'success': False, 'error': '缺少记录ID'}, ensure_ascii=False) + +sc_dbname = get_module_dbname('supplychain') +acc_dbname = get_module_dbname('accounting') +userorgid = await get_userorgid() + +# 查询supplychain_accounting记录 +db = DBPools() +async with db.sqlorContext(sc_dbname) as sor: + recs = await sor.sqlExe(""" + SELECT sa.*, sp.supplier_name, sr.sub_reseller_name + FROM supplychain_accounting sa + LEFT JOIN suppliers sp ON sa.supplier_id = sp.id COLLATE utf8mb4_unicode_ci + LEFT JOIN sub_resellers sr ON sa.sub_distributor_id = sr.id COLLATE utf8mb4_unicode_ci + WHERE sa.id = ${record_id}$ + """, {'record_id': record_id}) + +if not recs: + return json.dumps({'success': False, 'error': '记录不存在'}, ensure_ascii=False) + +rec = recs[0] + +# 构建settle_log +settle_log = { + 'accounting_orgid': userorgid, + 'providerid': rec.supplier_id or '', + 'sub_distributor_id': rec.sub_distributor_id or '', + 'sale_mode': '0', + 'settle_date': str(rec.sale_date or curDateString()), + 'settle_amt': float(rec.dist_amount or 0), + 'business_op': '分销商结算', + 'remark': remark +} + +# 调用SettleAccounting +try: + async with db.sqlorContext(acc_dbname) as acc_sor: + sa = SettleAccounting(settle_log) + await sa.accounting(acc_sor) + + # 更新sales_ledger结算状态 + async with db.sqlorContext(sc_dbname) as sc_sor: + await sc_sor.sqlExe(""" + UPDATE sales_ledger + SET settlement_status = '1', updated_at = NOW() + WHERE productid = ${productid}$ + AND sub_reseller_id = ${sub_distributor_id}$ + AND sale_date = ${sale_date}$ + """, { + 'productid': rec.productid, + 'sub_distributor_id': rec.sub_distributor_id, + 'sale_date': str(rec.sale_date) + }) + + debug(f'reseller_settlement: settled {record_id}, amt={rec.dist_amount}') + return json.dumps({ + 'success': True, + 'message': f'结算成功,金额: {rec.dist_amount}', + 'settle_id': sa.settleid, + 'bill_id': sa.billid + }, ensure_ascii=False, default=str) + +except Exception as e: + debug(f'reseller_settlement error: {format_exc()}') + return json.dumps({'success': False, 'error': f'结算失败: {str(e)}'}, ensure_ascii=False)