初始提交:飞球 ETL 系统全量代码

This commit is contained in:
Neo
2026-02-13 08:05:34 +08:00
commit 3c51f5485d
441 changed files with 117631 additions and 0 deletions

View File

View File

@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
"""助教作废事实表"""
from ..base_loader import BaseLoader
class AssistantAbolishLoader(BaseLoader):
"""写入 fact_assistant_abolish"""
def upsert_records(self, records: list) -> tuple:
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_assistant_abolish (
store_id,
abolish_id,
table_id,
table_name,
table_area_id,
table_area,
assistant_no,
assistant_name,
charge_minutes,
abolish_amount,
create_time,
trash_reason,
raw_data
)
VALUES (
%(store_id)s,
%(abolish_id)s,
%(table_id)s,
%(table_name)s,
%(table_area_id)s,
%(table_area)s,
%(assistant_no)s,
%(assistant_name)s,
%(charge_minutes)s,
%(abolish_amount)s,
%(create_time)s,
%(trash_reason)s,
%(raw_data)s
)
ON CONFLICT (store_id, abolish_id) DO UPDATE SET
table_id = EXCLUDED.table_id,
table_name = EXCLUDED.table_name,
table_area_id = EXCLUDED.table_area_id,
table_area = EXCLUDED.table_area,
assistant_no = EXCLUDED.assistant_no,
assistant_name = EXCLUDED.assistant_name,
charge_minutes = EXCLUDED.charge_minutes,
abolish_amount = EXCLUDED.abolish_amount,
create_time = EXCLUDED.create_time,
trash_reason = EXCLUDED.trash_reason,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(
sql, records, page_size=self._batch_size()
)
return (inserted, updated, 0)

View File

@@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
"""助教流水事实表"""
from ..base_loader import BaseLoader
class AssistantLedgerLoader(BaseLoader):
"""写入 fact_assistant_ledger"""
def upsert_ledgers(self, records: list) -> tuple:
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_assistant_ledger (
store_id,
ledger_id,
assistant_no,
assistant_name,
nickname,
level_name,
table_name,
ledger_unit_price,
ledger_count,
ledger_amount,
projected_income,
service_money,
member_discount_amount,
manual_discount_amount,
coupon_deduct_money,
order_trade_no,
order_settle_id,
operator_id,
operator_name,
assistant_team_id,
assistant_level,
site_table_id,
order_assistant_id,
site_assistant_id,
user_id,
ledger_start_time,
ledger_end_time,
start_use_time,
last_use_time,
income_seconds,
real_use_seconds,
is_trash,
trash_reason,
is_confirm,
ledger_status,
create_time,
raw_data
)
VALUES (
%(store_id)s,
%(ledger_id)s,
%(assistant_no)s,
%(assistant_name)s,
%(nickname)s,
%(level_name)s,
%(table_name)s,
%(ledger_unit_price)s,
%(ledger_count)s,
%(ledger_amount)s,
%(projected_income)s,
%(service_money)s,
%(member_discount_amount)s,
%(manual_discount_amount)s,
%(coupon_deduct_money)s,
%(order_trade_no)s,
%(order_settle_id)s,
%(operator_id)s,
%(operator_name)s,
%(assistant_team_id)s,
%(assistant_level)s,
%(site_table_id)s,
%(order_assistant_id)s,
%(site_assistant_id)s,
%(user_id)s,
%(ledger_start_time)s,
%(ledger_end_time)s,
%(start_use_time)s,
%(last_use_time)s,
%(income_seconds)s,
%(real_use_seconds)s,
%(is_trash)s,
%(trash_reason)s,
%(is_confirm)s,
%(ledger_status)s,
%(create_time)s,
%(raw_data)s
)
ON CONFLICT (store_id, ledger_id) DO UPDATE SET
assistant_no = EXCLUDED.assistant_no,
assistant_name = EXCLUDED.assistant_name,
nickname = EXCLUDED.nickname,
level_name = EXCLUDED.level_name,
table_name = EXCLUDED.table_name,
ledger_unit_price = EXCLUDED.ledger_unit_price,
ledger_count = EXCLUDED.ledger_count,
ledger_amount = EXCLUDED.ledger_amount,
projected_income = EXCLUDED.projected_income,
service_money = EXCLUDED.service_money,
member_discount_amount = EXCLUDED.member_discount_amount,
manual_discount_amount = EXCLUDED.manual_discount_amount,
coupon_deduct_money = EXCLUDED.coupon_deduct_money,
order_trade_no = EXCLUDED.order_trade_no,
order_settle_id = EXCLUDED.order_settle_id,
operator_id = EXCLUDED.operator_id,
operator_name = EXCLUDED.operator_name,
assistant_team_id = EXCLUDED.assistant_team_id,
assistant_level = EXCLUDED.assistant_level,
site_table_id = EXCLUDED.site_table_id,
order_assistant_id = EXCLUDED.order_assistant_id,
site_assistant_id = EXCLUDED.site_assistant_id,
user_id = EXCLUDED.user_id,
ledger_start_time = EXCLUDED.ledger_start_time,
ledger_end_time = EXCLUDED.ledger_end_time,
start_use_time = EXCLUDED.start_use_time,
last_use_time = EXCLUDED.last_use_time,
income_seconds = EXCLUDED.income_seconds,
real_use_seconds = EXCLUDED.real_use_seconds,
is_trash = EXCLUDED.is_trash,
trash_reason = EXCLUDED.trash_reason,
is_confirm = EXCLUDED.is_confirm,
ledger_status = EXCLUDED.ledger_status,
create_time = EXCLUDED.create_time,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(
sql, records, page_size=self._batch_size()
)
return (inserted, updated, 0)

View File

@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
"""券核销事实表"""
from ..base_loader import BaseLoader
class CouponUsageLoader(BaseLoader):
"""写入 fact_coupon_usage"""
def upsert_coupon_usage(self, records: list) -> tuple:
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_coupon_usage (
store_id,
usage_id,
coupon_code,
coupon_channel,
coupon_name,
sale_price,
coupon_money,
coupon_free_time,
use_status,
create_time,
consume_time,
operator_id,
operator_name,
table_id,
site_order_id,
group_package_id,
coupon_remark,
deal_id,
certificate_id,
verify_id,
is_delete,
raw_data
)
VALUES (
%(store_id)s,
%(usage_id)s,
%(coupon_code)s,
%(coupon_channel)s,
%(coupon_name)s,
%(sale_price)s,
%(coupon_money)s,
%(coupon_free_time)s,
%(use_status)s,
%(create_time)s,
%(consume_time)s,
%(operator_id)s,
%(operator_name)s,
%(table_id)s,
%(site_order_id)s,
%(group_package_id)s,
%(coupon_remark)s,
%(deal_id)s,
%(certificate_id)s,
%(verify_id)s,
%(is_delete)s,
%(raw_data)s
)
ON CONFLICT (store_id, usage_id) DO UPDATE SET
coupon_code = EXCLUDED.coupon_code,
coupon_channel = EXCLUDED.coupon_channel,
coupon_name = EXCLUDED.coupon_name,
sale_price = EXCLUDED.sale_price,
coupon_money = EXCLUDED.coupon_money,
coupon_free_time = EXCLUDED.coupon_free_time,
use_status = EXCLUDED.use_status,
create_time = EXCLUDED.create_time,
consume_time = EXCLUDED.consume_time,
operator_id = EXCLUDED.operator_id,
operator_name = EXCLUDED.operator_name,
table_id = EXCLUDED.table_id,
site_order_id = EXCLUDED.site_order_id,
group_package_id = EXCLUDED.group_package_id,
coupon_remark = EXCLUDED.coupon_remark,
deal_id = EXCLUDED.deal_id,
certificate_id = EXCLUDED.certificate_id,
verify_id = EXCLUDED.verify_id,
is_delete = EXCLUDED.is_delete,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(
sql, records, page_size=self._batch_size()
)
return (inserted, updated, 0)

View File

@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
"""库存变动事实表"""
from ..base_loader import BaseLoader
class InventoryChangeLoader(BaseLoader):
"""写入 fact_inventory_change"""
def upsert_changes(self, records: list) -> tuple:
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_inventory_change (
store_id,
change_id,
site_goods_id,
stock_type,
goods_name,
change_time,
start_qty,
end_qty,
change_qty,
unit,
price,
operator_name,
remark,
goods_category_id,
goods_second_category_id,
raw_data
)
VALUES (
%(store_id)s,
%(change_id)s,
%(site_goods_id)s,
%(stock_type)s,
%(goods_name)s,
%(change_time)s,
%(start_qty)s,
%(end_qty)s,
%(change_qty)s,
%(unit)s,
%(price)s,
%(operator_name)s,
%(remark)s,
%(goods_category_id)s,
%(goods_second_category_id)s,
%(raw_data)s
)
ON CONFLICT (store_id, change_id) DO UPDATE SET
site_goods_id = EXCLUDED.site_goods_id,
stock_type = EXCLUDED.stock_type,
goods_name = EXCLUDED.goods_name,
change_time = EXCLUDED.change_time,
start_qty = EXCLUDED.start_qty,
end_qty = EXCLUDED.end_qty,
change_qty = EXCLUDED.change_qty,
unit = EXCLUDED.unit,
price = EXCLUDED.price,
operator_name = EXCLUDED.operator_name,
remark = EXCLUDED.remark,
goods_category_id = EXCLUDED.goods_category_id,
goods_second_category_id = EXCLUDED.goods_second_category_id,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(
sql, records, page_size=self._batch_size()
)
return (inserted, updated, 0)

42
loaders/facts/order.py Normal file
View File

@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
"""订单事实表加载器"""
from ..base_loader import BaseLoader
class OrderLoader(BaseLoader):
"""订单数据加载器"""
def upsert_orders(self, records: list, store_id: int) -> tuple:
"""加载订单数据"""
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_order (
store_id, order_id, order_no, member_id, table_id,
order_time, end_time, total_amount, discount_amount,
final_amount, pay_status, order_status, remark, raw_data
)
VALUES (
%(store_id)s, %(order_id)s, %(order_no)s, %(member_id)s, %(table_id)s,
%(order_time)s, %(end_time)s, %(total_amount)s, %(discount_amount)s,
%(final_amount)s, %(pay_status)s, %(order_status)s, %(remark)s, %(raw_data)s
)
ON CONFLICT (store_id, order_id) DO UPDATE SET
order_no = EXCLUDED.order_no,
member_id = EXCLUDED.member_id,
table_id = EXCLUDED.table_id,
order_time = EXCLUDED.order_time,
end_time = EXCLUDED.end_time,
total_amount = EXCLUDED.total_amount,
discount_amount = EXCLUDED.discount_amount,
final_amount = EXCLUDED.final_amount,
pay_status = EXCLUDED.pay_status,
order_status = EXCLUDED.order_status,
remark = EXCLUDED.remark,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(sql, records, page_size=self._batch_size())
return (inserted, updated, 0)

61
loaders/facts/payment.py Normal file
View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
"""支付事实表加载器"""
from ..base_loader import BaseLoader
class PaymentLoader(BaseLoader):
"""支付数据加载器"""
def upsert_payments(self, records: list, store_id: int) -> tuple:
"""加载支付数据"""
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_payment (
store_id, pay_id, order_id,
site_id, tenant_id,
order_settle_id, order_trade_no,
relate_type, relate_id,
create_time, pay_time,
pay_amount, fee_amount, discount_amount,
payment_method, pay_type,
online_pay_channel, pay_terminal,
pay_status, remark, raw_data
)
VALUES (
%(store_id)s, %(pay_id)s, %(order_id)s,
%(site_id)s, %(tenant_id)s,
%(order_settle_id)s, %(order_trade_no)s,
%(relate_type)s, %(relate_id)s,
%(create_time)s, %(pay_time)s,
%(pay_amount)s, %(fee_amount)s, %(discount_amount)s,
%(payment_method)s, %(pay_type)s,
%(online_pay_channel)s, %(pay_terminal)s,
%(pay_status)s, %(remark)s, %(raw_data)s
)
ON CONFLICT (store_id, pay_id) DO UPDATE SET
order_settle_id = EXCLUDED.order_settle_id,
order_trade_no = EXCLUDED.order_trade_no,
relate_type = EXCLUDED.relate_type,
relate_id = EXCLUDED.relate_id,
order_id = EXCLUDED.order_id,
site_id = EXCLUDED.site_id,
tenant_id = EXCLUDED.tenant_id,
create_time = EXCLUDED.create_time,
pay_time = EXCLUDED.pay_time,
pay_amount = EXCLUDED.pay_amount,
fee_amount = EXCLUDED.fee_amount,
discount_amount = EXCLUDED.discount_amount,
payment_method = EXCLUDED.payment_method,
pay_type = EXCLUDED.pay_type,
online_pay_channel = EXCLUDED.online_pay_channel,
pay_terminal = EXCLUDED.pay_terminal,
pay_status = EXCLUDED.pay_status,
remark = EXCLUDED.remark,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(sql, records, page_size=self._batch_size())
return (inserted, updated, 0)

88
loaders/facts/refund.py Normal file
View File

@@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
"""退款事实表加载器"""
from ..base_loader import BaseLoader
class RefundLoader(BaseLoader):
"""写入 fact_refund"""
def upsert_refunds(self, records: list) -> tuple:
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_refund (
store_id,
refund_id,
site_id,
tenant_id,
pay_amount,
pay_status,
pay_time,
create_time,
relate_type,
relate_id,
payment_method,
refund_amount,
action_type,
pay_terminal,
operator_id,
channel_pay_no,
channel_fee,
is_delete,
member_id,
member_card_id,
raw_data
)
VALUES (
%(store_id)s,
%(refund_id)s,
%(site_id)s,
%(tenant_id)s,
%(pay_amount)s,
%(pay_status)s,
%(pay_time)s,
%(create_time)s,
%(relate_type)s,
%(relate_id)s,
%(payment_method)s,
%(refund_amount)s,
%(action_type)s,
%(pay_terminal)s,
%(operator_id)s,
%(channel_pay_no)s,
%(channel_fee)s,
%(is_delete)s,
%(member_id)s,
%(member_card_id)s,
%(raw_data)s
)
ON CONFLICT (store_id, refund_id) DO UPDATE SET
site_id = EXCLUDED.site_id,
tenant_id = EXCLUDED.tenant_id,
pay_amount = EXCLUDED.pay_amount,
pay_status = EXCLUDED.pay_status,
pay_time = EXCLUDED.pay_time,
create_time = EXCLUDED.create_time,
relate_type = EXCLUDED.relate_type,
relate_id = EXCLUDED.relate_id,
payment_method = EXCLUDED.payment_method,
refund_amount = EXCLUDED.refund_amount,
action_type = EXCLUDED.action_type,
pay_terminal = EXCLUDED.pay_terminal,
operator_id = EXCLUDED.operator_id,
channel_pay_no = EXCLUDED.channel_pay_no,
channel_fee = EXCLUDED.channel_fee,
is_delete = EXCLUDED.is_delete,
member_id = EXCLUDED.member_id,
member_card_id = EXCLUDED.member_card_id,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(
sql, records, page_size=self._batch_size()
)
return (inserted, updated, 0)

View File

@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
"""台费打折事实表"""
from ..base_loader import BaseLoader
class TableDiscountLoader(BaseLoader):
"""写入 fact_table_discount"""
def upsert_discounts(self, records: list) -> tuple:
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_table_discount (
store_id,
discount_id,
adjust_type,
applicant_id,
applicant_name,
operator_id,
operator_name,
ledger_amount,
ledger_count,
ledger_name,
ledger_status,
order_settle_id,
order_trade_no,
site_table_id,
table_area_id,
table_area_name,
create_time,
is_delete,
raw_data
)
VALUES (
%(store_id)s,
%(discount_id)s,
%(adjust_type)s,
%(applicant_id)s,
%(applicant_name)s,
%(operator_id)s,
%(operator_name)s,
%(ledger_amount)s,
%(ledger_count)s,
%(ledger_name)s,
%(ledger_status)s,
%(order_settle_id)s,
%(order_trade_no)s,
%(site_table_id)s,
%(table_area_id)s,
%(table_area_name)s,
%(create_time)s,
%(is_delete)s,
%(raw_data)s
)
ON CONFLICT (store_id, discount_id) DO UPDATE SET
adjust_type = EXCLUDED.adjust_type,
applicant_id = EXCLUDED.applicant_id,
applicant_name = EXCLUDED.applicant_name,
operator_id = EXCLUDED.operator_id,
operator_name = EXCLUDED.operator_name,
ledger_amount = EXCLUDED.ledger_amount,
ledger_count = EXCLUDED.ledger_count,
ledger_name = EXCLUDED.ledger_name,
ledger_status = EXCLUDED.ledger_status,
order_settle_id = EXCLUDED.order_settle_id,
order_trade_no = EXCLUDED.order_trade_no,
site_table_id = EXCLUDED.site_table_id,
table_area_id = EXCLUDED.table_area_id,
table_area_name = EXCLUDED.table_area_name,
create_time = EXCLUDED.create_time,
is_delete = EXCLUDED.is_delete,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(
sql, records, page_size=self._batch_size()
)
return (inserted, updated, 0)

188
loaders/facts/ticket.py Normal file
View File

@@ -0,0 +1,188 @@
# -*- coding: utf-8 -*-
"""小票详情加载器"""
from ..base_loader import BaseLoader
import json
class TicketLoader(BaseLoader):
"""
小票详情 JSON 解析加载器,写入 DWD 事实表。
处理:
- fact_order订单头
- fact_order_goods商品项
- fact_table_usage台桌使用
- fact_assistant_service助教服务
"""
def process_tickets(self, tickets: list, store_id: int) -> tuple:
"""
批量处理小票 JSON。
返回 (插入数, 错误数)
"""
inserted_count = 0
error_count = 0
# 准备批量数据列表
orders = []
goods_list = []
table_usages = []
assistant_services = []
for ticket in tickets:
try:
# 1. 解析订单头部 (fact_order)
root_data = ticket.get("data", {}).get("data", {})
if not root_data:
continue
order_settle_id = root_data.get("orderSettleId")
if not order_settle_id:
continue
orders.append({
"store_id": store_id,
"order_settle_id": order_settle_id,
"order_trade_no": 0,
"order_no": str(root_data.get("orderSettleNumber", "")),
"member_id": 0,
"pay_time": root_data.get("payTime"),
"total_amount": root_data.get("consumeMoney", 0),
"pay_amount": root_data.get("actualPayment", 0),
"discount_amount": root_data.get("memberOfferAmount", 0),
"coupon_amount": root_data.get("couponAmount", 0),
"status": "PAID",
"cashier_name": root_data.get("cashierName", ""),
"remark": root_data.get("orderRemark", ""),
"raw_data": json.dumps(ticket, ensure_ascii=False)
})
# 2. 解析订单项 (orderItem 列表)
order_items = root_data.get("orderItem", [])
for item in order_items:
order_trade_no = item.get("siteOrderId")
# 2.1 台桌流水
table_ledger = item.get("tableLedger")
if table_ledger:
table_usages.append({
"store_id": store_id,
"order_ledger_id": table_ledger.get("orderTableLedgerId"),
"order_settle_id": order_settle_id,
"table_id": table_ledger.get("siteTableId"),
"table_name": table_ledger.get("tableName"),
"start_time": table_ledger.get("chargeStartTime"),
"end_time": table_ledger.get("chargeEndTime"),
"duration_minutes": table_ledger.get("useDuration", 0),
"total_amount": table_ledger.get("consumptionAmount", 0),
"pay_amount": table_ledger.get("consumptionAmount", 0) - table_ledger.get("memberDiscountAmount", 0)
})
# 2.2 商品流水
goods_ledgers = item.get("goodsLedgers", [])
for g in goods_ledgers:
goods_list.append({
"store_id": store_id,
"order_goods_id": g.get("orderGoodsLedgerId"),
"order_settle_id": order_settle_id,
"order_trade_no": order_trade_no,
"goods_id": g.get("siteGoodsId"),
"goods_name": g.get("goodsName"),
"quantity": g.get("goodsCount", 0),
"unit_price": g.get("goodsPrice", 0),
"total_amount": g.get("ledgerAmount", 0),
"pay_amount": g.get("realGoodsMoney", 0)
})
# 2.3 助教服务
assistant_ledgers = item.get("assistantPlayWith", [])
for a in assistant_ledgers:
assistant_services.append({
"store_id": store_id,
"ledger_id": a.get("orderAssistantLedgerId"),
"order_settle_id": order_settle_id,
"assistant_id": a.get("assistantId"),
"assistant_name": a.get("ledgerName"),
"service_type": a.get("skillName", "Play"),
"start_time": a.get("ledgerStartTime"),
"end_time": a.get("ledgerEndTime"),
"duration_minutes": int(a.get("ledgerCount", 0) / 60) if a.get("ledgerCount") else 0,
"total_amount": a.get("ledgerAmount", 0),
"pay_amount": a.get("ledgerAmount", 0)
})
inserted_count += 1
except Exception as e:
self.logger.error(f"Error parsing ticket: {e}", exc_info=True)
error_count += 1
# 3. 批量插入/更新
if orders:
self._upsert_orders(orders)
if goods_list:
self._upsert_goods(goods_list)
if table_usages:
self._upsert_table_usages(table_usages)
if assistant_services:
self._upsert_assistant_services(assistant_services)
return inserted_count, error_count
def _upsert_orders(self, rows):
sql = """
INSERT INTO billiards.fact_order (
store_id, order_settle_id, order_trade_no, order_no, member_id,
pay_time, total_amount, pay_amount, discount_amount, coupon_amount,
status, cashier_name, remark, raw_data
) VALUES (
%(store_id)s, %(order_settle_id)s, %(order_trade_no)s, %(order_no)s, %(member_id)s,
%(pay_time)s, %(total_amount)s, %(pay_amount)s, %(discount_amount)s, %(coupon_amount)s,
%(status)s, %(cashier_name)s, %(remark)s, %(raw_data)s
)
ON CONFLICT (store_id, order_settle_id) DO UPDATE SET
pay_time = EXCLUDED.pay_time,
pay_amount = EXCLUDED.pay_amount,
updated_at = now()
"""
self.db.batch_execute(sql, rows)
def _upsert_goods(self, rows):
sql = """
INSERT INTO billiards.fact_order_goods (
store_id, order_goods_id, order_settle_id, order_trade_no,
goods_id, goods_name, quantity, unit_price, total_amount, pay_amount
) VALUES (
%(store_id)s, %(order_goods_id)s, %(order_settle_id)s, %(order_trade_no)s,
%(goods_id)s, %(goods_name)s, %(quantity)s, %(unit_price)s, %(total_amount)s, %(pay_amount)s
)
ON CONFLICT (store_id, order_goods_id) DO UPDATE SET
pay_amount = EXCLUDED.pay_amount
"""
self.db.batch_execute(sql, rows)
def _upsert_table_usages(self, rows):
sql = """
INSERT INTO billiards.fact_table_usage (
store_id, order_ledger_id, order_settle_id, table_id, table_name,
start_time, end_time, duration_minutes, total_amount, pay_amount
) VALUES (
%(store_id)s, %(order_ledger_id)s, %(order_settle_id)s, %(table_id)s, %(table_name)s,
%(start_time)s, %(end_time)s, %(duration_minutes)s, %(total_amount)s, %(pay_amount)s
)
ON CONFLICT (store_id, order_ledger_id) DO UPDATE SET
pay_amount = EXCLUDED.pay_amount
"""
self.db.batch_execute(sql, rows)
def _upsert_assistant_services(self, rows):
sql = """
INSERT INTO billiards.fact_assistant_service (
store_id, ledger_id, order_settle_id, assistant_id, assistant_name,
service_type, start_time, end_time, duration_minutes, total_amount, pay_amount
) VALUES (
%(store_id)s, %(ledger_id)s, %(order_settle_id)s, %(assistant_id)s, %(assistant_name)s,
%(service_type)s, %(start_time)s, %(end_time)s, %(duration_minutes)s, %(total_amount)s, %(pay_amount)s
)
ON CONFLICT (store_id, ledger_id) DO UPDATE SET
pay_amount = EXCLUDED.pay_amount
"""
self.db.batch_execute(sql, rows)

118
loaders/facts/topup.py Normal file
View File

@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
"""充值记录事实表"""
from ..base_loader import BaseLoader
class TopupLoader(BaseLoader):
"""写入 fact_topup"""
def upsert_topups(self, records: list) -> tuple:
if not records:
return (0, 0, 0)
sql = """
INSERT INTO billiards.fact_topup (
store_id,
topup_id,
member_id,
member_name,
member_phone,
card_id,
card_type_name,
pay_amount,
consume_money,
settle_status,
settle_type,
settle_name,
settle_relate_id,
pay_time,
create_time,
operator_id,
operator_name,
payment_method,
refund_amount,
cash_amount,
card_amount,
balance_amount,
online_amount,
rounding_amount,
adjust_amount,
goods_money,
table_charge_money,
service_money,
coupon_amount,
order_remark,
raw_data
)
VALUES (
%(store_id)s,
%(topup_id)s,
%(member_id)s,
%(member_name)s,
%(member_phone)s,
%(card_id)s,
%(card_type_name)s,
%(pay_amount)s,
%(consume_money)s,
%(settle_status)s,
%(settle_type)s,
%(settle_name)s,
%(settle_relate_id)s,
%(pay_time)s,
%(create_time)s,
%(operator_id)s,
%(operator_name)s,
%(payment_method)s,
%(refund_amount)s,
%(cash_amount)s,
%(card_amount)s,
%(balance_amount)s,
%(online_amount)s,
%(rounding_amount)s,
%(adjust_amount)s,
%(goods_money)s,
%(table_charge_money)s,
%(service_money)s,
%(coupon_amount)s,
%(order_remark)s,
%(raw_data)s
)
ON CONFLICT (store_id, topup_id) DO UPDATE SET
member_id = EXCLUDED.member_id,
member_name = EXCLUDED.member_name,
member_phone = EXCLUDED.member_phone,
card_id = EXCLUDED.card_id,
card_type_name = EXCLUDED.card_type_name,
pay_amount = EXCLUDED.pay_amount,
consume_money = EXCLUDED.consume_money,
settle_status = EXCLUDED.settle_status,
settle_type = EXCLUDED.settle_type,
settle_name = EXCLUDED.settle_name,
settle_relate_id = EXCLUDED.settle_relate_id,
pay_time = EXCLUDED.pay_time,
create_time = EXCLUDED.create_time,
operator_id = EXCLUDED.operator_id,
operator_name = EXCLUDED.operator_name,
payment_method = EXCLUDED.payment_method,
refund_amount = EXCLUDED.refund_amount,
cash_amount = EXCLUDED.cash_amount,
card_amount = EXCLUDED.card_amount,
balance_amount = EXCLUDED.balance_amount,
online_amount = EXCLUDED.online_amount,
rounding_amount = EXCLUDED.rounding_amount,
adjust_amount = EXCLUDED.adjust_amount,
goods_money = EXCLUDED.goods_money,
table_charge_money = EXCLUDED.table_charge_money,
service_money = EXCLUDED.service_money,
coupon_amount = EXCLUDED.coupon_amount,
order_remark = EXCLUDED.order_remark,
raw_data = EXCLUDED.raw_data,
updated_at = now()
RETURNING (xmax = 0) AS inserted
"""
inserted, updated = self.db.batch_upsert_with_returning(
sql, records, page_size=self._batch_size()
)
return (inserted, updated, 0)