v4.0.18版本提交
This commit is contained in:
@@ -415,3 +415,4 @@ export * from './dashboard-series';
|
||||
export * from './wecom-report';
|
||||
export * from './wecom-plugin';
|
||||
export * from './shipping-address';
|
||||
export * from './store-address';
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { formatStoreDisplayAddress } from './store-address';
|
||||
|
||||
describe('formatStoreDisplayAddress', () => {
|
||||
it('concatenates dropdown region with street-only detail', () => {
|
||||
expect(
|
||||
formatStoreDisplayAddress({
|
||||
province: '河南省',
|
||||
cityName: '郑州市',
|
||||
district: '金水区',
|
||||
address: '金水东路333号',
|
||||
}),
|
||||
).toBe('河南省郑州市金水区金水东路333号');
|
||||
});
|
||||
|
||||
it('does not strip region prefix already present in detail', () => {
|
||||
expect(
|
||||
formatStoreDisplayAddress({
|
||||
province: '河南省',
|
||||
cityName: '郑州市',
|
||||
district: '金水区',
|
||||
address: '河南省郑州市金水区金水东路333号',
|
||||
}),
|
||||
).toBe('河南省郑州市金水区河南省郑州市金水区金水东路333号');
|
||||
});
|
||||
|
||||
it('returns fallback when all parts are empty', () => {
|
||||
expect(formatStoreDisplayAddress({})).toBe('地址待完善');
|
||||
expect(formatStoreDisplayAddress({}, '')).toBe('');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
export const STORE_ADDRESS_FALLBACK = '地址待完善';
|
||||
|
||||
export type StoreAddressParts = {
|
||||
province?: string | null;
|
||||
cityName?: string | null;
|
||||
city?: string | null;
|
||||
district?: string | null;
|
||||
address?: string | null;
|
||||
};
|
||||
|
||||
function textPart(value: unknown): string {
|
||||
return typeof value === 'string' ? value.trim() : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 门店展示地址:省 + 市 + 区 + 详细地址,按字段原样拼接。
|
||||
* 省/市/区来自下拉选择,详细地址来自自由输入;即使详细地址已含省市区也不得去重。
|
||||
*/
|
||||
export function formatStoreDisplayAddress(
|
||||
store: StoreAddressParts,
|
||||
fallback = STORE_ADDRESS_FALLBACK,
|
||||
): string {
|
||||
const province = textPart(store.province);
|
||||
const city = textPart(store.cityName) || textPart(store.city);
|
||||
const district = textPart(store.district);
|
||||
const detail = textPart(store.address);
|
||||
const text = `${province}${city}${district}${detail}`;
|
||||
return text || fallback;
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
formatWecomReportMarkdown,
|
||||
WECOM_REPORT_EXCLUDED_ORDER_STATUSES,
|
||||
wecomReportCountedOrderWhere,
|
||||
wecomReportCutoff,
|
||||
wecomReportDueAt,
|
||||
wecomReportPeriod,
|
||||
@@ -24,6 +26,19 @@ const emptyStats = {
|
||||
redeemAmountIncrement: 40,
|
||||
};
|
||||
|
||||
describe('wecomReportCountedOrderWhere', () => {
|
||||
it('excludes pending pay, cancelled and refunding', () => {
|
||||
expect([...WECOM_REPORT_EXCLUDED_ORDER_STATUSES]).toEqual([
|
||||
'PENDING_PAY',
|
||||
'CANCELLED',
|
||||
'REFUNDING',
|
||||
]);
|
||||
expect(wecomReportCountedOrderWhere()).toEqual({
|
||||
status: { notIn: ['PENDING_PAY', 'CANCELLED', 'REFUNDING'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('wecomReportPeriod', () => {
|
||||
it('daily is the previous Shanghai calendar day (closed at send-day 00:00)', () => {
|
||||
const p = wecomReportPeriod('daily', new Date('2026-09-02T20:00:00+08:00'));
|
||||
|
||||
@@ -17,6 +17,20 @@ export function isWecomReportKind(v: string): v is WecomReportKind {
|
||||
return (WECOM_REPORT_KINDS as readonly string[]).includes(v);
|
||||
}
|
||||
|
||||
/** 经营报告/插件指标:订单笔数与金额均不计入待支付、已取消、退款中 */
|
||||
export const WECOM_REPORT_EXCLUDED_ORDER_STATUSES = [
|
||||
'PENDING_PAY',
|
||||
'CANCELLED',
|
||||
'REFUNDING',
|
||||
] as const;
|
||||
|
||||
export type WecomReportExcludedOrderStatus =
|
||||
(typeof WECOM_REPORT_EXCLUDED_ORDER_STATUSES)[number];
|
||||
|
||||
export function wecomReportCountedOrderWhere() {
|
||||
return { status: { notIn: [...WECOM_REPORT_EXCLUDED_ORDER_STATUSES] } };
|
||||
}
|
||||
|
||||
export type WecomReportStats = {
|
||||
usersTotal: number;
|
||||
usersIncrement: number;
|
||||
|
||||
@@ -29,6 +29,7 @@ export const HQ_LIST_COLUMN_KEYS = [
|
||||
'finance-partner-bills',
|
||||
'finance-winery-bills',
|
||||
'finance-logistics-bills',
|
||||
'finance-bank-accounts',
|
||||
'finance-store-withdrawals',
|
||||
'benefit-coupons',
|
||||
'benefit-ledgers',
|
||||
|
||||
@@ -74,6 +74,45 @@ export interface StoreBankAccountInputDto {
|
||||
bankBranch?: string;
|
||||
}
|
||||
|
||||
/** HQ 财务银行账户总目录类型(v4.0.18) */
|
||||
export const FINANCE_BANK_ACCOUNT_TYPES = ['STORE', 'WINERY', 'PARTNER', 'LOGISTICS', 'OTHER'] as const;
|
||||
export type FinanceBankAccountType = (typeof FINANCE_BANK_ACCOUNT_TYPES)[number];
|
||||
|
||||
export const FINANCE_BANK_ACCOUNT_TYPE_LABELS: Record<FinanceBankAccountType, string> = {
|
||||
STORE: '门店',
|
||||
WINERY: '酒厂',
|
||||
PARTNER: '合伙人',
|
||||
LOGISTICS: '物流',
|
||||
OTHER: '其他',
|
||||
};
|
||||
|
||||
export interface FinanceBankAccountDto {
|
||||
id: string;
|
||||
type: FinanceBankAccountType;
|
||||
ownerName: string;
|
||||
ownerId?: string | null;
|
||||
cityId?: string | null;
|
||||
cityName?: string | null;
|
||||
bankAccountName: string;
|
||||
bankAccountNo: string;
|
||||
bankBranch?: string | null;
|
||||
remark?: string | null;
|
||||
isDefault?: boolean;
|
||||
editable: boolean;
|
||||
}
|
||||
|
||||
export interface FinanceBankAccountInputDto {
|
||||
name?: string;
|
||||
bankAccountName: string;
|
||||
bankAccountNo: string;
|
||||
bankBranch?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface FinanceBankAccountRemarkDto {
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface StoreWithdrawSummaryDto {
|
||||
availableAmount: number;
|
||||
pendingReviewAmount: number;
|
||||
|
||||
@@ -75,6 +75,26 @@ export interface UpdateShopStaffRequest {
|
||||
storeIds?: string[];
|
||||
}
|
||||
|
||||
/** HQ 管理门店子账号:创建体与门店端一致,更新可改登录手机。 */
|
||||
export type CreateAdminStoreStaffRequest = CreateShopStaffRequest;
|
||||
|
||||
export interface UpdateAdminStoreStaffRequest extends UpdateShopStaffRequest {
|
||||
phone?: string;
|
||||
}
|
||||
|
||||
export interface AdminStoreStaffItem {
|
||||
id: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
staffRole: StoreStaffRole;
|
||||
permissions: string[];
|
||||
status: AccountStatus;
|
||||
storeIds: string[];
|
||||
stores: Array<{ id: string; name: string; status: string }>;
|
||||
lastLoginAt?: string | null;
|
||||
createdAt?: string;
|
||||
}
|
||||
|
||||
export const STORE_STAFF_ROLE_LABELS: Record<StoreStaffRole, string> = {
|
||||
MANAGER: '店长',
|
||||
CASHIER: '收银员',
|
||||
@@ -82,3 +102,8 @@ export const STORE_STAFF_ROLE_LABELS: Record<StoreStaffRole, string> = {
|
||||
|
||||
/** Default permissions for store sub-accounts (首版). */
|
||||
export const STORE_STAFF_DEFAULT_PERMISSIONS = ['redeem', 'records'] as const;
|
||||
|
||||
export const STORE_STAFF_PERMISSION_LABELS: Record<(typeof STORE_STAFF_DEFAULT_PERMISSIONS)[number], string> = {
|
||||
redeem: '核销',
|
||||
records: '核销记录',
|
||||
};
|
||||
|
||||
@@ -40,7 +40,7 @@ export const WECOM_PUSH_CONDITION_LABELS: Record<WecomPushCondition, string> = {
|
||||
'redeem.success': '门店核销成功',
|
||||
'invoice.pending': '发票申请待开票',
|
||||
'finance.store_bill': '门店日账单已生成',
|
||||
'finance.partner_bill': '合伙人月账单已生成',
|
||||
'finance.partner_bill': '合伙人账单',
|
||||
'finance.winery_bill': '酒厂日账单已生成',
|
||||
'finance.logistics_bill': '物流月对账已生成',
|
||||
};
|
||||
@@ -183,7 +183,7 @@ export const WECOM_TEMPLATE_EVENT_LABELS: Record<WecomTemplateEventKey, string>
|
||||
'store.withdraw_approved': '门店手动提现已通过',
|
||||
'invoice.pending': '发票申请待开票',
|
||||
'finance.store_bill': '门店日账单已生成',
|
||||
'finance.partner_bill': '合伙人月账单已生成',
|
||||
'finance.partner_bill': '合伙人账单',
|
||||
'finance.winery_bill': '酒厂日账单已生成',
|
||||
'finance.logistics_bill': '物流月对账已生成',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user