feat(freight): shop freight templates, server-side checkout fees, company dictionary (add-freight-templates)
This commit is contained in:
@@ -45,7 +45,11 @@ import type {
|
||||
ProductStatus,
|
||||
PublicFlashSaleSession,
|
||||
RedeemPointsBody,
|
||||
FreightTemplate,
|
||||
FreightTemplateInput,
|
||||
Shipment,
|
||||
ShippingCompany,
|
||||
ShippingQuote,
|
||||
Shop,
|
||||
ShopFlashSaleSession,
|
||||
ShopProfile,
|
||||
@@ -87,6 +91,7 @@ export interface ProductListQuery {
|
||||
export interface ProductUpsertBody {
|
||||
category_id?: string | null;
|
||||
brand_id?: string | null;
|
||||
freight_template_id?: string | null;
|
||||
slug: string;
|
||||
name: LocalizedText;
|
||||
description?: LocalizedText;
|
||||
@@ -100,6 +105,7 @@ export interface SkuUpsertBody {
|
||||
currency: string;
|
||||
stock: number;
|
||||
active?: boolean;
|
||||
weight_grams?: number | null;
|
||||
}
|
||||
|
||||
export interface ShipmentItemBody {
|
||||
@@ -248,6 +254,10 @@ export interface ApiClient {
|
||||
addAftersaleMessage(id: string, body: AftersaleMessageBody): Promise<AftersaleMessage>;
|
||||
/** Public points catalog: published products only. */
|
||||
listPointsProducts(): Promise<IntegralProduct[]>;
|
||||
/** Server-computed per-shop shipping fees for the current cart + address. */
|
||||
quoteShipping(address: Address, currency: string): Promise<ShippingQuote>;
|
||||
/** Public shipping-company dictionary. */
|
||||
listShippingCompanies(): Promise<ShippingCompany[]>;
|
||||
listMyRedemptions(): Promise<IntegralOrder[]>;
|
||||
redeemPoints(body: RedeemPointsBody): Promise<IntegralOrder>;
|
||||
/** Public: active flash-sale sessions with their purchasable items. */
|
||||
@@ -272,6 +282,7 @@ export interface ApiClient {
|
||||
carrier: string,
|
||||
trackingNo: string,
|
||||
items: ShipmentItemBody[],
|
||||
shippingCompanyCode?: string,
|
||||
): Promise<Shipment>;
|
||||
listShipments(): Promise<Shipment[]>;
|
||||
markShipped(id: string): Promise<Shipment>;
|
||||
@@ -302,6 +313,10 @@ export interface ApiClient {
|
||||
confirmAftersaleReceipt(id: string): Promise<Aftersale>;
|
||||
refundAftersale(id: string): Promise<Aftersale>;
|
||||
addAftersaleMessage(id: string, body: AftersaleMessageBody): Promise<AftersaleMessage>;
|
||||
listFreightTemplates(): Promise<FreightTemplate[]>;
|
||||
createFreightTemplate(body: FreightTemplateInput): Promise<FreightTemplate>;
|
||||
updateFreightTemplate(id: string, body: FreightTemplateInput): Promise<FreightTemplate>;
|
||||
deleteFreightTemplate(id: string): Promise<void>;
|
||||
};
|
||||
admin: {
|
||||
listUsers(page?: number): Promise<Paged<User>>;
|
||||
@@ -359,6 +374,9 @@ export function createApi(opts: ApiClientOptions): ApiClient {
|
||||
payOrder: (id) => r("POST", `/orders/${id}/pay`),
|
||||
confirmDelivered: (shipmentId) => r("POST", `/shipments/${shipmentId}/confirm-delivered`),
|
||||
listMyShipments: () => r("GET", "/shipments"),
|
||||
quoteShipping: (address, currency) =>
|
||||
r("POST", "/orders/shipping-quote", { shipping_address: address, currency }),
|
||||
listShippingCompanies: () => r("GET", "/shipping/companies"),
|
||||
requestInvoice: (orderId, title, taxNo, kind) =>
|
||||
r("POST", `/orders/${orderId}/invoice`, { title, tax_no: taxNo, kind }),
|
||||
listMyInvoices: () => r("GET", "/invoices"),
|
||||
@@ -403,10 +421,11 @@ export function createApi(opts: ApiClientOptions): ApiClient {
|
||||
upsertSku: (productId, body) => r("POST", `/shop/products/${productId}/skus`, body),
|
||||
listOrders: (q = {}) => r("GET", "/shop/orders", undefined, { ...q }),
|
||||
getOrder: (id) => r("GET", `/shop/orders/${id}`),
|
||||
createShipment: (orderId, carrier, trackingNo, items) =>
|
||||
createShipment: (orderId, carrier, trackingNo, items, shippingCompanyCode) =>
|
||||
r("POST", `/shop/orders/${orderId}/shipments`, {
|
||||
carrier,
|
||||
tracking_no: trackingNo,
|
||||
shipping_company_code: shippingCompanyCode ?? null,
|
||||
items,
|
||||
}),
|
||||
listShipments: () => r("GET", "/shop/shipments"),
|
||||
@@ -437,6 +456,10 @@ export function createApi(opts: ApiClientOptions): ApiClient {
|
||||
confirmAftersaleReceipt: (id) => r("POST", `/shop/aftersales/${id}/confirm-receipt`),
|
||||
refundAftersale: (id) => r("POST", `/shop/aftersales/${id}/refund`),
|
||||
addAftersaleMessage: (id, body) => r("POST", `/shop/aftersales/${id}/messages`, body),
|
||||
listFreightTemplates: () => r("GET", "/shop/freight-templates"),
|
||||
createFreightTemplate: (body) => r("POST", "/shop/freight-templates", body),
|
||||
updateFreightTemplate: (id, body) => r("PUT", `/shop/freight-templates/${id}`, body),
|
||||
deleteFreightTemplate: (id) => r("DELETE", `/shop/freight-templates/${id}`),
|
||||
},
|
||||
admin: {
|
||||
listUsers: (page = 1) => r("GET", "/admin/users", undefined, { page }),
|
||||
|
||||
@@ -68,6 +68,8 @@ export interface Product {
|
||||
description: LocalizedText;
|
||||
images: string[];
|
||||
status: ProductStatus;
|
||||
/** Freight template of the same shop; overrides the shop default. */
|
||||
freight_template_id?: string | null;
|
||||
created_at: string;
|
||||
/** Units sold across paid orders; every product payload carries it. */
|
||||
sold_count: number;
|
||||
@@ -97,6 +99,8 @@ export interface Sku {
|
||||
currency: string;
|
||||
stock: number;
|
||||
active: boolean;
|
||||
/** Grams per unit for by-weight freight; null lines contribute zero weight. */
|
||||
weight_grams?: number | null;
|
||||
}
|
||||
|
||||
export interface Currency {
|
||||
@@ -142,6 +146,9 @@ export interface OrderItem {
|
||||
image: string | null;
|
||||
/** Set when this line received flash-sale pricing. */
|
||||
flash_sale_item_id: string | null;
|
||||
/** Freight template + pricing method snapshotted at checkout. */
|
||||
freight_template_id?: string | null;
|
||||
freight_pricing_method?: FreightPricingMethod | null;
|
||||
}
|
||||
|
||||
export interface Order {
|
||||
@@ -156,6 +163,8 @@ export interface Order {
|
||||
discount_minor: number;
|
||||
/** Authoritative sum of completed refunds, integer minor units. */
|
||||
refund_total_minor: number;
|
||||
/** Server-computed shipping fee for this shop order. */
|
||||
shipping_fee_minor: number;
|
||||
/** The coupon this order redeemed, or null. */
|
||||
coupon_id: string | null;
|
||||
/** The group-buying activity this order joined, or null. */
|
||||
@@ -473,6 +482,8 @@ export interface Shipment {
|
||||
status: ShipmentStatus;
|
||||
/** Not returned by the API; only shipment creation sends line items. */
|
||||
items?: { order_item_id: string; qty: number }[];
|
||||
/** Dictionary code of the company the merchant shipped with. */
|
||||
shipping_company_code?: string | null;
|
||||
shipped_at: string | null;
|
||||
delivered_at: string | null;
|
||||
created_at: string;
|
||||
@@ -695,3 +706,74 @@ export interface AftersaleReturnTrackingBody {
|
||||
}
|
||||
|
||||
export type AftersaleArbitration = "refund" | "reject";
|
||||
|
||||
// ---- freight / shipping ----
|
||||
|
||||
export type FreightPricingMethod = "by_piece" | "by_weight";
|
||||
|
||||
export interface FreightRegionRule {
|
||||
id: string;
|
||||
/** Region names/codes matched case-insensitively against the address region fields. */
|
||||
regions: string[];
|
||||
first_fee_minor: number;
|
||||
first_unit: number;
|
||||
additional_fee_minor: number;
|
||||
additional_unit: number;
|
||||
}
|
||||
|
||||
export interface FreightRegionRuleInput {
|
||||
regions: string[];
|
||||
first_fee_minor: number;
|
||||
first_unit: number;
|
||||
additional_fee_minor: number;
|
||||
additional_unit: number;
|
||||
}
|
||||
|
||||
export interface FreightTemplate {
|
||||
id: string;
|
||||
shop_id: string;
|
||||
name: string;
|
||||
is_default: boolean;
|
||||
always_free: boolean;
|
||||
pricing_method: FreightPricingMethod;
|
||||
first_fee_minor: number;
|
||||
/** Pieces for by_piece, grams for by_weight. */
|
||||
first_unit: number;
|
||||
additional_fee_minor: number;
|
||||
additional_unit: number;
|
||||
free_threshold_minor: number | null;
|
||||
region_rules: FreightRegionRule[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface FreightTemplateInput {
|
||||
name: string;
|
||||
is_default?: boolean;
|
||||
always_free?: boolean;
|
||||
pricing_method: FreightPricingMethod;
|
||||
first_fee_minor: number;
|
||||
first_unit: number;
|
||||
additional_fee_minor: number;
|
||||
additional_unit: number;
|
||||
free_threshold_minor?: number | null;
|
||||
region_rules?: FreightRegionRuleInput[];
|
||||
}
|
||||
|
||||
export interface ShippingCompany {
|
||||
code: string;
|
||||
name: LocalizedText;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export interface ShippingQuoteShop {
|
||||
shop_id: string;
|
||||
fee_minor: number;
|
||||
}
|
||||
|
||||
/** Server-computed per-shop shipping fees for the current cart and address. */
|
||||
export interface ShippingQuote {
|
||||
currency: string;
|
||||
shops: ShippingQuoteShop[];
|
||||
total_minor: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user