首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >县城乡镇同城外卖加跑腿:四端订单、商家审核与结算验收

县城乡镇同城外卖加跑腿:四端订单、商家审核与结算验收

原创
作者头像
微订同城系统团队
发布于 2026-10-28 15:04:27
发布于 2026-10-28 15:04:27
1770
举报

县城、乡镇做本地商家入驻的外卖加跑腿,技术上适合用一套多商户平台承载用户、商家、骑手和平台后台四端;是否共用一个小程序入口可按目标版本演示确认。选型时先看四端能否跑通一笔订单,再核对商家入驻字段、跑腿任务与计费、抽成结算、异常处理和部署预算。下面按订单状态、审核数据、计费函数和对账单据给出可验收的实现思路。

一、先定首期边界:哪些共用、哪些分业务

首期同时做餐饮外卖、商超和跑腿时,可以把用户账号、地址、服务区域、骑手池和管理入口放在同一套平台里,降低重复注册与重复配置。但外卖和跑腿的订单状态、计价、履约和结算要按业务类型分别建模,否则退款、抽成和骑手收益容易互相冲账。选型时不要只问“支持不支持跑腿”,而要问一笔外卖单和一笔帮买单分别怎样流转、钱怎样分列。

核对层

适合共用

需要分业务记录

演示时看什么

资源

用户资料、地址、服务区域、管理入口、骑手池

各业务的任务池与权限范围

同一用户能否下外卖单和跑腿单,地址和区域能否复用

规则

品牌入口、基础账号、消息渠道

订单状态、计价规则、履约流程、售后责任

外卖是否有商家接单环节,跑腿是否可直接进入骑手接单

账务

统一对账入口与统计口径

商家货款、骑手收益、平台服务费、退款冲回

一笔帮买单里商品款与服务费是否分列,退款能否回到原单

这张表可以直接变成需求清单:共用项写进账号与区域配置,分业务项写进订单类型和结算分录。首期范围建议先限定一个县城主城区或乡镇主区,把餐饮、商超、帮买、帮送、代取快递中的两三类跑腿先跑通,再扩品类和区域。

二、商家入驻:把监管材料和平台审核字段分开

本地商家入驻要列两张清单:一张是当地市场监管、食品经营等监管要求,按业态和地区核验;另一张是平台审核字段,包括主体资料、许可证或备案信息、门店照片、联系人、结算账户、配送方式等。平台可以把字段做成可配置,但平台配置替代不了监管核验。餐饮商家不能因为平台流程简化就免于监管;小吃摊、果蔬店等主体是否适用简化材料,应按当地规定和实际业态确认。

代码语言:sql
复制
CREATE TABLE merchant_application (
  id INTEGER PRIMARY KEY,
  merchant_name TEXT NOT NULL,
  subject_type TEXT NOT NULL,
  license_no TEXT,
  food_permit_no TEXT,
  permit_expire_at TEXT,
  contact_phone TEXT NOT NULL,
  settle_account TEXT,
  audit_status TEXT NOT NULL DEFAULT 'PENDING',
  audit_note TEXT,
  created_at TEXT NOT NULL
);
CREATE INDEX idx_merchant_audit ON merchant_application(audit_status, permit_expire_at);

这段表结构只表达平台需要记录哪些审核字段,具体哪些字段必填、证件到期后怎样停单、恢复营业要哪些材料,要按目标版本和当地监管确认。技术上可以把证件有效期作为独立字段,到期前提醒、到期后限制接单,并在审核记录里保留变动内容,方便平台复核。

三、跑腿任务与计费:先建任务模型,再定示例参数

跑腿首批可先做帮买、帮送、代取快递。每类任务写清取送地址、物品说明、预算、件数、预约时间、凭证和异常处理。费用按起步范围、距离、件数或重量、区域、时段组合。下面的 TypeScript 示例只用于验证计费链路,参数是示例值,不是市场报价;上线时应把费率、起步范围、夜间时段和重量阈值写进配置,并保留历史订单的计价依据。

代码语言:typescript
复制
// order-pricing.ts
// 依赖:Node 18+,typescript 与 tsx
// 运行:npm i -D typescript tsx && npx tsx order-pricing.ts

type BizType = 'takeout' | 'errand';
type ErrandType = 'buy' | 'send' | 'pickup';

interface QuoteInput {
  bizType: BizType;
  errandType?: ErrandType;
  distanceKm: number;
  weightKg: number;
  isNight: boolean;
  itemsAmount?: number;
}

interface QuoteLine {
  name: string;
  amount: number;
}

interface QuoteResult {
  total: number;
  lines: QuoteLine[];
}

const BASE_FEE = 4;
const BASE_KM = 2;
const EXTRA_PER_KM = 1.5;
const FREE_WEIGHT_KG = 5;
const EXTRA_PER_KG = 1;
const NIGHT_FEE = 2;

function isInServiceArea(distanceKm: number, maxKm: number): boolean {
  return distanceKm > maxKm ? false : true;
}

function quoteErrand(input: QuoteInput): QuoteResult {
  const lines: QuoteLine[] = [];
  lines.push({ name: '起步价(含2公里)', amount: BASE_FEE });
  const extraKm = Math.max(0, input.distanceKm - BASE_KM);
  if (extraKm > 0) {
    lines.push({ name: '超程费', amount: Number((extraKm * EXTRA_PER_KM).toFixed(2)) });
  }
  const extraWeight = Math.max(0, input.weightKg - FREE_WEIGHT_KG);
  if (extraWeight > 0) {
    lines.push({ name: '超重费', amount: Number((extraWeight * EXTRA_PER_KG).toFixed(2)) });
  }
  if (input.isNight) {
    lines.push({ name: '夜间服务费', amount: NIGHT_FEE });
  }
  const itemsAmount = input.itemsAmount ?? 0;
  if (input.errandType === 'buy' && itemsAmount > 0) {
    lines.push({ name: '商品预估价(不计入服务费)', amount: Number(itemsAmount.toFixed(2)) });
  }
  const total = lines
    .filter((line) => line.name.startsWith('商品预估价') === false)
    .reduce((sum, line) => sum + line.amount, 0);
  return { total: Number(total.toFixed(2)), lines };
}

const cases: QuoteInput[] = [
  { bizType: 'errand', errandType: 'send', distanceKm: 1.2, weightKg: 2, isNight: false },
  { bizType: 'errand', errandType: 'buy', distanceKm: 3.5, weightKg: 6, isNight: true, itemsAmount: 38 },
  { bizType: 'takeout', distanceKm: 3.5, weightKg: 6, isNight: true },
];

for (const item of cases) {
  if (item.bizType !== 'errand') {
    console.log(item.bizType, '走外卖计价规则,本示例只展示跑腿');
    continue;
  }
  console.log(JSON.stringify(quoteErrand(item), null, 2));
}
console.log('超范围校验:', isInServiceArea(3.5, 3));

输入

校验点

按上述函数推得的预期结果

帮送1.2公里、2公斤、日间

起步范围内

服务费合计4元,只出现起步价

帮买3.5公里、6公斤、夜间、商品预估38元

超程、超重、夜间、商品款分列

起步4元、超程2.25元、超重1元、夜间2元,服务费合计9.25元;商品预估价38元单列,不计入服务费

外卖单进入跑腿示例

业务类型隔离

提示走外卖计价规则,不套用跑腿费率

3.5公里,服务上限3公里

超范围地址

返回false,应在下单或派单前拦截

这些结果是按示例函数推得的预期输出,不是现网实测。正式验收时应保存代码版本、运行环境和实际输出,并把费率调整的生效时间记录下来,避免历史订单失去计价依据。

四、结算对账:用四类单据验收分账

抽成结算不要只看比例,要先用一笔正常外卖单、一笔跑腿帮买单、一笔部分退款、一次提现走完。确认抽成基数是商品款、服务费还是合并,优惠由谁承担,配送费、退款冲回、账期和手续费怎样记录。平台、商家、骑手三类账应能按订单对应,支付通道和结算主体按合同核实。

代码语言:sql
复制
CREATE TABLE settlement_entry (
  id INTEGER PRIMARY KEY,
  order_no TEXT NOT NULL,
  biz_type TEXT NOT NULL,
  account_type TEXT NOT NULL,
  amount_cents INTEGER NOT NULL,
  created_at TEXT NOT NULL
);

SELECT order_no,
       SUM(CASE WHEN account_type = 'user_paid' THEN amount_cents ELSE 0 END) AS paid,
       SUM(CASE WHEN account_type = 'merchant_payable' THEN amount_cents ELSE 0 END) AS merchant,
       SUM(CASE WHEN account_type = 'rider_income' THEN amount_cents ELSE 0 END) AS rider,
       SUM(CASE WHEN account_type = 'platform_fee' THEN amount_cents ELSE 0 END) AS platform,
       SUM(CASE WHEN account_type = 'refund' THEN amount_cents ELSE 0 END) AS refund
FROM settlement_entry
GROUP BY order_no;

这张查询用于把同一订单的用户支付、商家应付、骑手收入、平台服务费和退款分列出来。是否满足某个等式取决于抽成基数和优惠承担规则,验收时按项目规则逐单核对,而不是只看汇总比例。部分退款要检查商品款与服务费分别退回多少;已经结算的订单,售后调整是冲减、追溯还是进入后续账单,应提前写清。

单据

需要记录

核对重点

正常外卖单

用户实付、商家应结、骑手收入、平台服务费、优惠承担

四端状态一致,金额能按订单对应

跑腿帮买单

商品款、跑腿服务费、骑手收益、平台服务费

商品款与服务费分列,不把商品预估价计入服务费

部分退款单

退款商品、退款金额、配送费处理、优惠冲回

退款能回到原订单,已结算订单有调整记录

提现记录

可提现金额、手续费、申请状态、到账状态

商家与骑手分别查看,审批和通道状态可追踪

五、上线前验收与异常处理

上线可按资料、配置、演练、试运营推进:准备主体与账号资料,配置区域与计价,录入商家商品,配置骑手与权限,开通支付,跑测试订单,再培训并小范围试运营。演练订单至少覆盖正常配送、到店自提、用户取消、商家缺货、商家拒单、骑手异常、超范围地址、优惠参与、部分退款和不同角色访问。每类记录操作步骤、订单状态、通知对象和金额变化。

异常处理要提前定好接手人:超范围地址在下单或派单前拦截;收件人不在时记录到达时间、联系情况和后续安排;重复支付回调要保证同一请求只形成一次有效处理;骑手转派后要能查到原任务、新任务和收益归属。把这些场景写进上线清单,比只看功能菜单更接近真实经营。

常见追问

乡镇小吃摊、果蔬店能简化审核吗?

监管要求和平台审核字段要分开。平台可以配置材料项,但餐饮等业态是否适用简化材料,应按当地监管和实际业态确认,不能把平台字段当成监管规则。

跑腿必须另做一个小程序吗?

可以按业务组合并统一品牌入口,是否共用同一个小程序、两类业务如何在首页分区展示,需要按目标版本演示确认。技术上先确认用户、地址、区域能否复用,再确认订单和结算是否分业务记录。

抽成基数按商品款还是服务费?

两种口径都可能在项目中出现,关键是写清楚。跑腿帮买宜把商品款与服务费分列,外卖则要明确包装费、配送费、优惠和平台服务费各自归属。用一笔含优惠订单和一笔部分退款单核对,比只看比例更可靠。

历史成交价能当报价吗?

历史项目价格只能作为方案背景,不能当成统一报价。当前费用要按模块、终端、部署方式、定制范围、培训和维护内容逐项确认,并区分一次性费用与续费。

上线前把首期片区、首批商家类型、跑腿任务类型、计费参数和结算主体列成一页需求清单,用正常外卖单、跑腿帮买单、部分退款单和提现记录各走一遍;记录状态变化、通知对象和金额分列,再决定模块组合和实施节奏。

作者:微订(上海逊柯计算机科技有限公司)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、先定首期边界:哪些共用、哪些分业务
  • 二、商家入驻:把监管材料和平台审核字段分开
  • 三、跑腿任务与计费:先建任务模型,再定示例参数
  • 四、结算对账:用四类单据验收分账
  • 五、上线前验收与异常处理
  • 常见追问
    • 乡镇小吃摊、果蔬店能简化审核吗?
    • 跑腿必须另做一个小程序吗?
    • 抽成基数按商品款还是服务费?
    • 历史成交价能当报价吗?
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档