/** 企微结算账单正文:分字段块 + 字节上限(机器人 markdown 约 4096 字节) */ export type WecomBankLike = { bankAccountName?: string | null; bankName?: string | null; bankBranch?: string | null; bankAccountNo?: string | null; }; export function formatYuan(n: number): string { return `¥${Number(n).toFixed(2)}`; } export function formatPercent(rate: number): string { const p = Number(rate) * 100; if (!Number.isFinite(p)) return '—'; const rounded = Math.round(p * 100) / 100; const text = Number.isInteger(rounded) ? String(rounded) : String(rounded); return `${text}%`; } export function formatPartnerDashLabel( company?: string | null, name?: string | null, ): string { const person = (name || '').trim() || '—'; const org = (company || '').trim(); return org ? `${org}-${person}` : person; } export function wecomBankParts(bank?: WecomBankLike | null): { payee: string; accountNo: string; bankBranch: string; } { if (!bank) return { payee: '未登记', accountNo: '—', bankBranch: '—' }; const payee = bank.bankAccountName?.trim() || ''; const accountNo = bank.bankAccountNo?.trim() || ''; const bankBranch = bank.bankName?.trim() || bank.bankBranch?.trim() || ''; if (!payee && !accountNo) { return { payee: '未登记', accountNo: '—', bankBranch: bankBranch || '—' }; } return { payee: payee || '—', accountNo: accountNo || '—', bankBranch: bankBranch || '—', }; } export function formatWecomFieldBlock(rows: Array<[string, string]>): string { return rows.map(([k, v]) => `${k}:${v}`).join('\n'); } export function joinLimited(names: string[], unit: string, max = 8): string { const uniq = [...new Set(names.map((n) => n.trim()).filter(Boolean))]; if (!uniq.length) return '—'; if (uniq.length <= max) return uniq.join('、'); return `${uniq.slice(0, max).join('、')} 等${uniq.length}${unit}`; } const BILL_DIGEST_MAX_BYTES = 3200; export function capBillBlocks(blocks: string[]): string { if (!blocks.length) return '无'; const out: string[] = []; let bytes = 0; let shown = 0; for (const block of blocks) { const extra = (shown ? 2 : 0) + Buffer.byteLength(block, 'utf8'); if (shown > 0 && bytes + extra > BILL_DIGEST_MAX_BYTES) { out.push(`另有 ${blocks.length - shown} 笔未列出,请到 HQ 查看`); break; } out.push(block); bytes += extra; shown += 1; } return out.join('\n\n'); } export function formatStoreBillWecomBlock(row: { cityName: string; storeName: string; partnerLabel: string; redeemCount: number; redeemAmount: number; settlementRate: number; amount: number; bank?: WecomBankLike | null; }): string { const bank = wecomBankParts(row.bank); return formatWecomFieldBlock([ ['城市', row.cityName || '—'], ['门店', row.storeName || '—'], ['合伙人', row.partnerLabel || '—'], ['核销笔数', String(row.redeemCount)], ['核销金额', formatYuan(row.redeemAmount)], ['结算比例', formatPercent(row.settlementRate)], ['账单', formatYuan(row.amount)], ['收款人', bank.payee], ['收款账户', bank.accountNo], ['收款开户行', bank.bankBranch], ]); } export function formatPartnerBillWecomBlock(row: { cityName: string; partnerLabel: string; orderCount?: number; redeemCount?: number; orderCommission: number; redeemCommission: number; amount: number; bank?: WecomBankLike | null; }): string { const bank = wecomBankParts(row.bank); const rows: Array<[string, string]> = [ ['城市', row.cityName || '—'], ['合伙人', row.partnerLabel || '—'], ]; if (row.orderCount != null) rows.push(['订单笔数', String(row.orderCount)]); if (row.redeemCount != null) rows.push(['核销笔数', String(row.redeemCount)]); rows.push( ['订单佣金', formatYuan(row.orderCommission)], ['核销佣金', formatYuan(row.redeemCommission)], ['账单', formatYuan(row.amount)], ['收款人', bank.payee], ['收款账户', bank.accountNo], ['收款开户行', bank.bankBranch], ); return formatWecomFieldBlock(rows); } export function formatLogisticsBillWecomBlock(row: { cityNames: string; partnerNames: string; providerName: string; settlementMethod: string; orderCount: number; bottleCount: number; amount: number; bank?: WecomBankLike | null; }): string { const bank = wecomBankParts(row.bank); return formatWecomFieldBlock([ ['城市', row.cityNames || '—'], ['合伙人', row.partnerNames || '—'], ['承运商', row.providerName || '—'], ['结算方式', row.settlementMethod || '—'], ['发货笔数', String(row.orderCount)], ['瓶数', String(row.bottleCount)], ['账单', formatYuan(row.amount)], ['收款人', bank.payee], ['收款账户', bank.accountNo], ['收款开户行', bank.bankBranch], ]); }