feat: 客户出口资质备案与申报要素,9610 预报直连下游
All checks were successful
Build and Deploy / deploy (push) Successful in 1m49s
All checks were successful
Build and Deploy / deploy (push) Successful in 1m49s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
e5c9364434
commit
8ce8b82f48
28
db.sql
28
db.sql
@ -261,6 +261,30 @@ CREATE TABLE `t_customer_sender_address` (
|
|||||||
KEY `idx_csa_customer_default` (`CustomerId`, `AddressType`, `IsDefault`)
|
KEY `idx_csa_customer_default` (`CustomerId`, `AddressType`, `IsDefault`)
|
||||||
) COMMENT='客户地址簿(发件/退件/收件)';
|
) COMMENT='客户地址簿(发件/退件/收件)';
|
||||||
|
|
||||||
|
CREATE TABLE `t_customer_export_qualification` (
|
||||||
|
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`CustomerId` INT NOT NULL COMMENT '归属客户 t_customer.Id',
|
||||||
|
`CompanyName` VARCHAR(200) NOT NULL COMMENT '企业名称',
|
||||||
|
`SocialCreditCode` VARCHAR(64) NOT NULL COMMENT '企业社会信用代码',
|
||||||
|
`DomesticConsignor` VARCHAR(200) NOT NULL COMMENT '境内发货人',
|
||||||
|
`DomesticConsignorCustomsCode` VARCHAR(64) NULL COMMENT '境内发货人海关代码',
|
||||||
|
`ProducerName` VARCHAR(200) NOT NULL COMMENT '生产销售单位',
|
||||||
|
`ProducerCustomsCode` VARCHAR(64) NULL COMMENT '生产销售单位海关代码',
|
||||||
|
`CustomsPort` VARCHAR(100) NULL COMMENT '备案海关港口地',
|
||||||
|
`IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认:0-否,1-是(同客户仅一条)',
|
||||||
|
`Remark` VARCHAR(512) NULL COMMENT '备注',
|
||||||
|
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
|
||||||
|
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
|
||||||
|
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
|
||||||
|
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`UpdateUserId` INT NULL COMMENT '更新人',
|
||||||
|
`UpdateTime` DATETIME NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
KEY `idx_ceq_customer` (`CustomerId`, `IsDeleted`, `Id`),
|
||||||
|
KEY `idx_ceq_credit` (`SocialCreditCode`, `IsDeleted`),
|
||||||
|
KEY `idx_ceq_customer_default` (`CustomerId`, `IsDefault`)
|
||||||
|
) COMMENT='客户出口资质备案';
|
||||||
|
|
||||||
CREATE TABLE `t_order_template` (
|
CREATE TABLE `t_order_template` (
|
||||||
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
|
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
|
||||||
`Name` VARCHAR(64) NOT NULL COMMENT '模板名称',
|
`Name` VARCHAR(64) NOT NULL COMMENT '模板名称',
|
||||||
@ -403,6 +427,7 @@ CREATE TABLE `t_order_declaration` (
|
|||||||
`HsCode` VARCHAR(50) NULL COMMENT 'HsCode',
|
`HsCode` VARCHAR(50) NULL COMMENT 'HsCode',
|
||||||
`ImHsCode` VARCHAR(50) NULL COMMENT '进口HsCode',
|
`ImHsCode` VARCHAR(50) NULL COMMENT '进口HsCode',
|
||||||
`ExHsCode` VARCHAR(50) NULL COMMENT '出口HsCode',
|
`ExHsCode` VARCHAR(50) NULL COMMENT '出口HsCode',
|
||||||
|
`DeclareElement` VARCHAR(255) NULL COMMENT '出口申报要素',
|
||||||
`SkuImage` VARCHAR(512) NULL COMMENT '图片(存 storage key 或短 URL)',
|
`SkuImage` VARCHAR(512) NULL COMMENT '图片(存 storage key 或短 URL)',
|
||||||
`Category` VARCHAR(20) NULL COMMENT '类别',
|
`Category` VARCHAR(20) NULL COMMENT '类别',
|
||||||
`Brand` VARCHAR(50) NULL COMMENT '品牌',
|
`Brand` VARCHAR(50) NULL COMMENT '品牌',
|
||||||
@ -1351,6 +1376,7 @@ CREATE TABLE `c_sku` (
|
|||||||
`UnitPrice` DECIMAL(12,4) NULL COMMENT '单价',
|
`UnitPrice` DECIMAL(12,4) NULL COMMENT '单价',
|
||||||
`ExHsCode` VARCHAR(64) NULL COMMENT '出口HSCode',
|
`ExHsCode` VARCHAR(64) NULL COMMENT '出口HSCode',
|
||||||
`ImHsCode` VARCHAR(64) NULL COMMENT '进口HSCode',
|
`ImHsCode` VARCHAR(64) NULL COMMENT '进口HSCode',
|
||||||
|
`DeclareElement` VARCHAR(255) NULL COMMENT '出口申报要素',
|
||||||
`WeightG` DECIMAL(10,2) NULL COMMENT '重量(g)',
|
`WeightG` DECIMAL(10,2) NULL COMMENT '重量(g)',
|
||||||
`LengthCm` DECIMAL(10,2) NULL COMMENT '长(cm)',
|
`LengthCm` DECIMAL(10,2) NULL COMMENT '长(cm)',
|
||||||
`WidthCm` DECIMAL(10,2) NULL COMMENT '宽(cm)',
|
`WidthCm` DECIMAL(10,2) NULL COMMENT '宽(cm)',
|
||||||
@ -1998,7 +2024,7 @@ CREATE TABLE `t_9610_order_item` (
|
|||||||
`Sku` VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'SKU(对齐 t_order_declaration.Sku)',
|
`Sku` VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'SKU(对齐 t_order_declaration.Sku)',
|
||||||
`CnName` VARCHAR(250) NOT NULL DEFAULT '' COMMENT '中文品名(对齐 t_order_declaration.CnName)',
|
`CnName` VARCHAR(250) NOT NULL DEFAULT '' COMMENT '中文品名(对齐 t_order_declaration.CnName)',
|
||||||
`ExHsCode` VARCHAR(10) NULL COMMENT '出口海关编码(对齐 t_order_declaration.ExHsCode)',
|
`ExHsCode` VARCHAR(10) NULL COMMENT '出口海关编码(对齐 t_order_declaration.ExHsCode)',
|
||||||
`DeclareElement` VARCHAR(255) NULL COMMENT '申报要素',
|
`DeclareElement` VARCHAR(255) NULL COMMENT '出口申报要素',
|
||||||
`Barcode` VARCHAR(255) NULL COMMENT '条形码',
|
`Barcode` VARCHAR(255) NULL COMMENT '条形码',
|
||||||
`DestCountry` VARCHAR(255) NULL COMMENT '目的国(地区)代码',
|
`DestCountry` VARCHAR(255) NULL COMMENT '目的国(地区)代码',
|
||||||
`ItemCurrency` VARCHAR(3) NULL COMMENT '币制',
|
`ItemCurrency` VARCHAR(3) NULL COMMENT '币制',
|
||||||
|
|||||||
98
sql/migrate_customer_export_qualification.sql
Normal file
98
sql/migrate_customer_export_qualification.sql
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
-- 存量库:客户出口资质备案表(含 IsDefault / Remark)
|
||||||
|
-- 可重复执行。
|
||||||
|
-- 目标表:t_customer_export_qualification
|
||||||
|
|
||||||
|
SET @db := DATABASE();
|
||||||
|
|
||||||
|
-- 1) 表不存在则整表创建
|
||||||
|
SET @exists := (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM information_schema.TABLES
|
||||||
|
WHERE TABLE_SCHEMA = @db
|
||||||
|
AND TABLE_NAME = 't_customer_export_qualification'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @sql := IF(
|
||||||
|
@exists = 0,
|
||||||
|
'CREATE TABLE `t_customer_export_qualification` (
|
||||||
|
`Id` INT NOT NULL AUTO_INCREMENT COMMENT ''主键'',
|
||||||
|
`CustomerId` INT NOT NULL COMMENT ''归属客户 t_customer.Id'',
|
||||||
|
`CompanyName` VARCHAR(200) NOT NULL COMMENT ''企业名称'',
|
||||||
|
`SocialCreditCode` VARCHAR(64) NOT NULL COMMENT ''企业社会信用代码'',
|
||||||
|
`DomesticConsignor` VARCHAR(200) NOT NULL COMMENT ''境内发货人'',
|
||||||
|
`DomesticConsignorCustomsCode` VARCHAR(64) NULL COMMENT ''境内发货人海关代码'',
|
||||||
|
`ProducerName` VARCHAR(200) NOT NULL COMMENT ''生产销售单位'',
|
||||||
|
`ProducerCustomsCode` VARCHAR(64) NULL COMMENT ''生产销售单位海关代码'',
|
||||||
|
`CustomsPort` VARCHAR(100) NULL COMMENT ''备案海关港口地'',
|
||||||
|
`IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT ''是否默认:0-否,1-是(同客户仅一条)'',
|
||||||
|
`Remark` VARCHAR(512) NULL COMMENT ''备注'',
|
||||||
|
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT ''软删除:0-否,1-是'',
|
||||||
|
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT ''并发戳'',
|
||||||
|
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT ''创建人'',
|
||||||
|
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''创建时间'',
|
||||||
|
`UpdateUserId` INT NULL COMMENT ''更新人'',
|
||||||
|
`UpdateTime` DATETIME NULL COMMENT ''更新时间'',
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
KEY `idx_ceq_customer` (`CustomerId`, `IsDeleted`, `Id`),
|
||||||
|
KEY `idx_ceq_credit` (`SocialCreditCode`, `IsDeleted`),
|
||||||
|
KEY `idx_ceq_customer_default` (`CustomerId`, `IsDefault`)
|
||||||
|
) COMMENT=''客户出口资质备案''',
|
||||||
|
'SELECT ''t_customer_export_qualification already exists'' AS info'
|
||||||
|
);
|
||||||
|
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- 2) 已建表但缺 IsDefault 时补列
|
||||||
|
SET @col := (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @db
|
||||||
|
AND TABLE_NAME = 't_customer_export_qualification'
|
||||||
|
AND COLUMN_NAME = 'IsDefault'
|
||||||
|
);
|
||||||
|
SET @sql := IF(
|
||||||
|
@col = 0,
|
||||||
|
'ALTER TABLE `t_customer_export_qualification`
|
||||||
|
ADD COLUMN `IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT ''是否默认:0-否,1-是(同客户仅一条)'' AFTER `CustomsPort`',
|
||||||
|
'SELECT ''IsDefault already exists'' AS info'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- 3) 已建表但缺 Remark 时补列
|
||||||
|
SET @col := (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @db
|
||||||
|
AND TABLE_NAME = 't_customer_export_qualification'
|
||||||
|
AND COLUMN_NAME = 'Remark'
|
||||||
|
);
|
||||||
|
SET @sql := IF(
|
||||||
|
@col = 0,
|
||||||
|
'ALTER TABLE `t_customer_export_qualification`
|
||||||
|
ADD COLUMN `Remark` VARCHAR(512) NULL COMMENT ''备注'' AFTER `IsDefault`',
|
||||||
|
'SELECT ''Remark already exists'' AS info'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- 4) 默认索引
|
||||||
|
SET @idx := (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM information_schema.STATISTICS
|
||||||
|
WHERE TABLE_SCHEMA = @db
|
||||||
|
AND TABLE_NAME = 't_customer_export_qualification'
|
||||||
|
AND INDEX_NAME = 'idx_ceq_customer_default'
|
||||||
|
);
|
||||||
|
SET @sql := IF(
|
||||||
|
@idx = 0,
|
||||||
|
'ALTER TABLE `t_customer_export_qualification` ADD KEY `idx_ceq_customer_default` (`CustomerId`, `IsDefault`)',
|
||||||
|
'SELECT ''idx_ceq_customer_default already exists'' AS info'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
38
sql/migrate_declare_element.sql
Normal file
38
sql/migrate_declare_element.sql
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
-- 存量库:SKU / 订单申报增加「出口申报要素」DeclareElement
|
||||||
|
-- 可重复执行;仅在列不存在时 ADD。
|
||||||
|
|
||||||
|
SET @db := DATABASE();
|
||||||
|
|
||||||
|
-- c_sku.DeclareElement
|
||||||
|
SET @exists := (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @db
|
||||||
|
AND TABLE_NAME = 'c_sku'
|
||||||
|
AND COLUMN_NAME = 'DeclareElement'
|
||||||
|
);
|
||||||
|
SET @sql := IF(
|
||||||
|
@exists = 0,
|
||||||
|
'ALTER TABLE `c_sku` ADD COLUMN `DeclareElement` VARCHAR(255) NULL COMMENT ''出口申报要素'' AFTER `ImHsCode`',
|
||||||
|
'SELECT ''c_sku.DeclareElement already exists'' AS info'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- t_order_declaration.DeclareElement
|
||||||
|
SET @exists := (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @db
|
||||||
|
AND TABLE_NAME = 't_order_declaration'
|
||||||
|
AND COLUMN_NAME = 'DeclareElement'
|
||||||
|
);
|
||||||
|
SET @sql := IF(
|
||||||
|
@exists = 0,
|
||||||
|
'ALTER TABLE `t_order_declaration` ADD COLUMN `DeclareElement` VARCHAR(255) NULL COMMENT ''出口申报要素'' AFTER `ExHsCode`',
|
||||||
|
'SELECT ''t_order_declaration.DeclareElement already exists'' AS info'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Oms.Application.Dtos.Customers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口资质备案分页查询。
|
||||||
|
/// </summary>
|
||||||
|
public class CustomerExportQualificationPaginatedInput
|
||||||
|
{
|
||||||
|
[Newtonsoft.Json.JsonProperty("page")]
|
||||||
|
public int Page { get; set; } = 1;
|
||||||
|
|
||||||
|
[Newtonsoft.Json.JsonProperty("pageSize")]
|
||||||
|
public int PageSize { get; set; } = 50;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 客户 ID(管理端可选;不传则查全部)。
|
||||||
|
/// </summary>
|
||||||
|
[Newtonsoft.Json.JsonProperty("customerId")]
|
||||||
|
public int? CustomerId { get; set; }
|
||||||
|
|
||||||
|
[Newtonsoft.Json.JsonProperty("keyword")]
|
||||||
|
public string? Keyword { get; set; }
|
||||||
|
|
||||||
|
[Newtonsoft.Json.JsonProperty("onlyDefault")]
|
||||||
|
public bool OnlyDefault { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新增出口资质备案。
|
||||||
|
/// </summary>
|
||||||
|
public class CreateCustomerExportQualificationInput
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 客户 ID(管理端代操作必传;客户门户可省略)。
|
||||||
|
/// </summary>
|
||||||
|
public int? CustomerId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(200)]
|
||||||
|
public string CompanyName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(64)]
|
||||||
|
public string SocialCreditCode { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(200)]
|
||||||
|
public string DomesticConsignor { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[StringLength(64)]
|
||||||
|
public string? DomesticConsignorCustomsCode { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(200)]
|
||||||
|
public string ProducerName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[StringLength(64)]
|
||||||
|
public string? ProducerCustomsCode { get; set; }
|
||||||
|
|
||||||
|
[StringLength(100)]
|
||||||
|
public string? CustomsPort { get; set; }
|
||||||
|
|
||||||
|
public bool IsDefault { get; set; }
|
||||||
|
|
||||||
|
[StringLength(512)]
|
||||||
|
public string? Remark { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新出口资质备案。
|
||||||
|
/// </summary>
|
||||||
|
public class UpdateCustomerExportQualificationInput : CreateCustomerExportQualificationInput
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public int Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口资质备案出参。
|
||||||
|
/// </summary>
|
||||||
|
public class CustomerExportQualificationOutput
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int CustomerId { get; set; }
|
||||||
|
|
||||||
|
public string CompanyName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string SocialCreditCode { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string DomesticConsignor { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string? DomesticConsignorCustomsCode { get; set; }
|
||||||
|
|
||||||
|
public string ProducerName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string? ProducerCustomsCode { get; set; }
|
||||||
|
|
||||||
|
public string? CustomsPort { get; set; }
|
||||||
|
|
||||||
|
public bool IsDefault { get; set; }
|
||||||
|
|
||||||
|
public string? Remark { get; set; }
|
||||||
|
|
||||||
|
public DateTime? CreateTime { get; set; }
|
||||||
|
|
||||||
|
public DateTime? UpdateTime { get; set; }
|
||||||
|
}
|
||||||
@ -301,6 +301,14 @@ public class Customs9610DeclareResult
|
|||||||
public int? HttpStatusCode { get; set; }
|
public int? HttpStatusCode { get; set; }
|
||||||
|
|
||||||
public string? ResponseBody { get; set; }
|
public string? ResponseBody { get; set; }
|
||||||
|
|
||||||
|
public string? Url { get; set; }
|
||||||
|
|
||||||
|
public string? RequestJson { get; set; }
|
||||||
|
|
||||||
|
public string? ServiceNo { get; set; }
|
||||||
|
|
||||||
|
public string? ClientNo { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Customs9610DeclareBatchOutput
|
public class Customs9610DeclareBatchOutput
|
||||||
|
|||||||
@ -65,6 +65,11 @@ public class OrderItemOutput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? ExHsCode { get; set; }
|
public string? ExHsCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口申报要素。
|
||||||
|
/// </summary>
|
||||||
|
public string? DeclareElement { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SKU 图片。
|
/// SKU 图片。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -60,6 +60,11 @@ public class OrderParcelItemInput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? ExHsCode { get; set; }
|
public string? ExHsCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口申报要素。
|
||||||
|
/// </summary>
|
||||||
|
public string? DeclareElement { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SKU 图片。
|
/// SKU 图片。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -42,6 +42,11 @@ public class WarehouseSkuOutput
|
|||||||
|
|
||||||
public string? ImHsCode { get; set; }
|
public string? ImHsCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口申报要素。
|
||||||
|
/// </summary>
|
||||||
|
public string? DeclareElement { get; set; }
|
||||||
|
|
||||||
public decimal? WeightG { get; set; }
|
public decimal? WeightG { get; set; }
|
||||||
|
|
||||||
public decimal? LengthCm { get; set; }
|
public decimal? LengthCm { get; set; }
|
||||||
@ -81,6 +86,11 @@ public class WarehouseSkuSaveInput
|
|||||||
|
|
||||||
public string? ImHsCode { get; set; }
|
public string? ImHsCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口申报要素。
|
||||||
|
/// </summary>
|
||||||
|
public string? DeclareElement { get; set; }
|
||||||
|
|
||||||
public decimal? WeightG { get; set; }
|
public decimal? WeightG { get; set; }
|
||||||
|
|
||||||
public decimal? LengthCm { get; set; }
|
public decimal? LengthCm { get; set; }
|
||||||
|
|||||||
@ -32,4 +32,14 @@ public interface IItfxForwardClient
|
|||||||
string appSecret,
|
string appSecret,
|
||||||
object body,
|
object body,
|
||||||
CancellationToken cancellationToken = default);
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 向指定绝对 URL 发起 ForwardWithSubscribe(用于写死网关地址的场景)。
|
||||||
|
/// </summary>
|
||||||
|
Task<ItfxForwardResult> ForwardToAbsoluteUrlAsync(
|
||||||
|
string absoluteUrl,
|
||||||
|
string appKey,
|
||||||
|
string appSecret,
|
||||||
|
object body,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,6 +64,23 @@ internal sealed class ItfxForwardClient(
|
|||||||
var root = $"{settings.BaseUrl.Trim().TrimEnd('/')}/InterfaceForward/ForwardWithSubscribe";
|
var root = $"{settings.BaseUrl.Trim().TrimEnd('/')}/InterfaceForward/ForwardWithSubscribe";
|
||||||
var url =
|
var url =
|
||||||
$"{root}?standardCode={Uri.EscapeDataString(standardCode.Trim())}&supplierCode={Uri.EscapeDataString(supplierCode.Trim())}";
|
$"{root}?standardCode={Uri.EscapeDataString(standardCode.Trim())}&supplierCode={Uri.EscapeDataString(supplierCode.Trim())}";
|
||||||
|
return await ForwardToAbsoluteUrlAsync(url, appKey, appSecret, body, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ItfxForwardResult> ForwardToAbsoluteUrlAsync(
|
||||||
|
string absoluteUrl,
|
||||||
|
string appKey,
|
||||||
|
string appSecret,
|
||||||
|
object body,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(absoluteUrl))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Itfx absoluteUrl is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
var settings = await configProvider.GetAsync(cancellationToken);
|
||||||
|
var url = absoluteUrl.Trim();
|
||||||
var requestJson = JsonSerializer.Serialize(body, JsonOptions);
|
var requestJson = JsonSerializer.Serialize(body, JsonOptions);
|
||||||
|
|
||||||
using var request = new HttpRequestMessage(HttpMethod.Post, url);
|
using var request = new HttpRequestMessage(HttpMethod.Post, url);
|
||||||
|
|||||||
@ -0,0 +1,239 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using Fake.Application;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Oms.Application.Dtos.Customers;
|
||||||
|
using Oms.Application.Dtos.Shared;
|
||||||
|
using Oms.Application.Shared;
|
||||||
|
using Oms.Domain.CustomersAggregate.Entities;
|
||||||
|
using Oms.Domain.CustomersAggregate.Repositories;
|
||||||
|
|
||||||
|
namespace Oms.Application.Services.Customers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 客户出口资质备案 API。
|
||||||
|
/// </summary>
|
||||||
|
[ApiExplorerSettings(GroupName = "OMS-Customer")]
|
||||||
|
public class CustomerExportQualificationService : ApplicationService
|
||||||
|
{
|
||||||
|
private ICustomerRepository CustomerRepository =>
|
||||||
|
LazyServiceProvider.GetRequiredService<ICustomerRepository>();
|
||||||
|
|
||||||
|
private ICustomerExportQualificationRepository ExportQualificationRepository =>
|
||||||
|
LazyServiceProvider.GetRequiredService<ICustomerExportQualificationRepository>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口资质备案分页列表。
|
||||||
|
/// 管理端未传 customerId 时查询全部;客户门户仅查自身。
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("/customer/export-qualification/list")]
|
||||||
|
public async Task<OmsPageResult<CustomerExportQualificationOutput>> GetListAsync(
|
||||||
|
[FromBody] CustomerExportQualificationPaginatedInput input)
|
||||||
|
{
|
||||||
|
var customerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
|
||||||
|
CustomerRepository,
|
||||||
|
CurrentUser,
|
||||||
|
input.CustomerId);
|
||||||
|
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
|
||||||
|
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
|
||||||
|
var predicate = BuildPredicate(customerId, input);
|
||||||
|
|
||||||
|
var (entities, total) = await RepositoryPageHelper.GetPageAsync(
|
||||||
|
ExportQualificationRepository,
|
||||||
|
predicate,
|
||||||
|
pageIndex,
|
||||||
|
pageSize,
|
||||||
|
q => q.OrderByDescending(x => x.IsDefault).ThenByDescending(x => x.Id));
|
||||||
|
|
||||||
|
return new OmsPageResult<CustomerExportQualificationOutput>
|
||||||
|
{
|
||||||
|
Items = entities.Select(MapOutput).ToList(),
|
||||||
|
Total = total
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口资质备案详情。
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("/customer/export-qualification/detail")]
|
||||||
|
public async Task<CustomerExportQualificationOutput> GetDetailAsync(
|
||||||
|
[FromQuery] int id,
|
||||||
|
[FromQuery] int? customerId = null)
|
||||||
|
{
|
||||||
|
var entity = await GetOwnedOrThrowAsync(id, customerId);
|
||||||
|
return MapOutput(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新增出口资质备案。
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("/customer/export-qualification/create")]
|
||||||
|
public async Task<object> CreateAsync([FromBody] CreateCustomerExportQualificationInput input)
|
||||||
|
{
|
||||||
|
var customerId = await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
|
||||||
|
CustomerRepository,
|
||||||
|
CurrentUser,
|
||||||
|
input.CustomerId);
|
||||||
|
ValidateInput(input);
|
||||||
|
|
||||||
|
if (input.IsDefault)
|
||||||
|
{
|
||||||
|
await ExportQualificationRepository.ClearDefaultAsync(customerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
var entity = new CustomerExportQualification
|
||||||
|
{
|
||||||
|
CustomerId = customerId,
|
||||||
|
CompanyName = input.CompanyName.Trim(),
|
||||||
|
SocialCreditCode = input.SocialCreditCode.Trim(),
|
||||||
|
DomesticConsignor = input.DomesticConsignor.Trim(),
|
||||||
|
DomesticConsignorCustomsCode = TrimOrNull(input.DomesticConsignorCustomsCode),
|
||||||
|
ProducerName = input.ProducerName.Trim(),
|
||||||
|
ProducerCustomsCode = TrimOrNull(input.ProducerCustomsCode),
|
||||||
|
CustomsPort = TrimOrNull(input.CustomsPort),
|
||||||
|
IsDefault = input.IsDefault ? (byte)1 : (byte)0,
|
||||||
|
Remark = TrimOrNull(input.Remark)
|
||||||
|
};
|
||||||
|
|
||||||
|
entity = await ExportQualificationRepository.InsertAsync(entity);
|
||||||
|
return new { id = entity.Id };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新出口资质备案。
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("/customer/export-qualification/update")]
|
||||||
|
public async Task UpdateAsync([FromBody] UpdateCustomerExportQualificationInput input)
|
||||||
|
{
|
||||||
|
var entity = await GetOwnedOrThrowAsync(input.Id, input.CustomerId);
|
||||||
|
ValidateInput(input);
|
||||||
|
|
||||||
|
if (input.IsDefault)
|
||||||
|
{
|
||||||
|
await ExportQualificationRepository.ClearDefaultAsync(entity.CustomerId, entity.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.CompanyName = input.CompanyName.Trim();
|
||||||
|
entity.SocialCreditCode = input.SocialCreditCode.Trim();
|
||||||
|
entity.DomesticConsignor = input.DomesticConsignor.Trim();
|
||||||
|
entity.DomesticConsignorCustomsCode = TrimOrNull(input.DomesticConsignorCustomsCode);
|
||||||
|
entity.ProducerName = input.ProducerName.Trim();
|
||||||
|
entity.ProducerCustomsCode = TrimOrNull(input.ProducerCustomsCode);
|
||||||
|
entity.CustomsPort = TrimOrNull(input.CustomsPort);
|
||||||
|
entity.IsDefault = input.IsDefault ? (byte)1 : (byte)0;
|
||||||
|
entity.Remark = TrimOrNull(input.Remark);
|
||||||
|
|
||||||
|
await ExportQualificationRepository.UpdateAsync(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除出口资质备案(软删)。
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("/customer/export-qualification/delete")]
|
||||||
|
public async Task DeleteAsync([FromBody] IdInput input)
|
||||||
|
{
|
||||||
|
var entity = await GetOwnedOrThrowAsync(input.Id, null);
|
||||||
|
await ExportQualificationRepository.DeleteAsync(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设为默认出口资质备案(同客户仅一条)。
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("/customer/export-qualification/set-default")]
|
||||||
|
public async Task SetDefaultAsync([FromBody] IdInput input)
|
||||||
|
{
|
||||||
|
var entity = await GetOwnedOrThrowAsync(input.Id, null);
|
||||||
|
await ExportQualificationRepository.ClearDefaultAsync(entity.CustomerId, entity.Id);
|
||||||
|
entity.IsDefault = 1;
|
||||||
|
await ExportQualificationRepository.UpdateAsync(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<CustomerExportQualification> GetOwnedOrThrowAsync(int id, int? requestedCustomerId)
|
||||||
|
{
|
||||||
|
var customerId = await WarehouseCustomerHelper.ResolveListCustomerIdAsync(
|
||||||
|
CustomerRepository,
|
||||||
|
CurrentUser,
|
||||||
|
requestedCustomerId);
|
||||||
|
var (hasCustomerFilter, customerIdValue) = WarehouseCustomerHelper.ToCustomerFilter(customerId);
|
||||||
|
|
||||||
|
var entity = hasCustomerFilter
|
||||||
|
? await ExportQualificationRepository.GetOwnedAsync(id, customerIdValue)
|
||||||
|
: await ExportQualificationRepository.FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new BusinessException("出口资质备案不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateInput(CreateCustomerExportQualificationInput input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(input.CompanyName))
|
||||||
|
{
|
||||||
|
throw new BusinessException("企业名称不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(input.SocialCreditCode))
|
||||||
|
{
|
||||||
|
throw new BusinessException("企业社会信用代码不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(input.DomesticConsignor))
|
||||||
|
{
|
||||||
|
throw new BusinessException("境内发货人不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(input.ProducerName))
|
||||||
|
{
|
||||||
|
throw new BusinessException("生产销售单位不能为空");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Expression<Func<CustomerExportQualification, bool>> BuildPredicate(
|
||||||
|
int? customerId,
|
||||||
|
CustomerExportQualificationPaginatedInput input)
|
||||||
|
{
|
||||||
|
var (hasCustomerFilter, customerIdValue) = WarehouseCustomerHelper.ToCustomerFilter(customerId);
|
||||||
|
var keyword = input.Keyword?.Trim();
|
||||||
|
var hasKeyword = !string.IsNullOrWhiteSpace(keyword);
|
||||||
|
var onlyDefault = input.OnlyDefault;
|
||||||
|
|
||||||
|
return x =>
|
||||||
|
(!hasCustomerFilter || x.CustomerId == customerIdValue)
|
||||||
|
&& (!onlyDefault || x.IsDefault == 1)
|
||||||
|
&& (!hasKeyword
|
||||||
|
|| x.CompanyName.Contains(keyword!)
|
||||||
|
|| x.SocialCreditCode.Contains(keyword!)
|
||||||
|
|| x.DomesticConsignor.Contains(keyword!)
|
||||||
|
|| (x.DomesticConsignorCustomsCode != null && x.DomesticConsignorCustomsCode.Contains(keyword!))
|
||||||
|
|| x.ProducerName.Contains(keyword!)
|
||||||
|
|| (x.ProducerCustomsCode != null && x.ProducerCustomsCode.Contains(keyword!))
|
||||||
|
|| (x.CustomsPort != null && x.CustomsPort.Contains(keyword!))
|
||||||
|
|| (x.Remark != null && x.Remark.Contains(keyword!)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CustomerExportQualificationOutput MapOutput(CustomerExportQualification entity)
|
||||||
|
{
|
||||||
|
return new CustomerExportQualificationOutput
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CustomerId = entity.CustomerId,
|
||||||
|
CompanyName = entity.CompanyName,
|
||||||
|
SocialCreditCode = entity.SocialCreditCode,
|
||||||
|
DomesticConsignor = entity.DomesticConsignor,
|
||||||
|
DomesticConsignorCustomsCode = entity.DomesticConsignorCustomsCode,
|
||||||
|
ProducerName = entity.ProducerName,
|
||||||
|
ProducerCustomsCode = entity.ProducerCustomsCode,
|
||||||
|
CustomsPort = entity.CustomsPort,
|
||||||
|
IsDefault = entity.IsDefault > 0,
|
||||||
|
Remark = entity.Remark,
|
||||||
|
CreateTime = entity.CreateTime,
|
||||||
|
UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? TrimOrNull(string? value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -242,17 +242,138 @@ public class Customs9610OrderService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 批量获取报关单(调 API 中心上游,标准码暂定)。
|
/// 预报下游(写死 create9610Order / BH 网关地址)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPost("/order/customs-9610/fetch-declaration-form-batch")]
|
[HttpPost("/order/customs-9610/fetch-declaration-form-batch")]
|
||||||
public async Task<Customs9610DeclareBatchOutput> FetchDeclarationFormBatchAsync([FromBody] Customs9610IdsInput input)
|
public async Task<Customs9610DeclareBatchOutput> FetchDeclarationFormBatchAsync([FromBody] Customs9610IdsInput input)
|
||||||
{
|
{
|
||||||
return await FetchDocumentBatchAsync(
|
var results = new List<Customs9610DeclareResult>();
|
||||||
input,
|
foreach (var id in input.Ids.Where(x => x > 0).Distinct())
|
||||||
settings => string.IsNullOrWhiteSpace(settings.Customs9610DeclarationFormStandardCode)
|
{
|
||||||
? "customs9610DeclarationForm"
|
try
|
||||||
: settings.Customs9610DeclarationFormStandardCode.Trim(),
|
{
|
||||||
"获取报关单");
|
results.Add(await DownstreamForwardOneAsync(id));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
results.Add(new Customs9610DeclareResult
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Success = false,
|
||||||
|
Message = string.IsNullOrWhiteSpace(ex.Message) ? "预报下游失败" : ex.Message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Customs9610DeclareBatchOutput
|
||||||
|
{
|
||||||
|
SuccessCount = results.Count(x => x.Success),
|
||||||
|
FailCount = results.Count(x => !x.Success),
|
||||||
|
Items = results,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 写死的 9610 预报下游地址:create9610Order + supplierCode=BH。
|
||||||
|
/// </summary>
|
||||||
|
private const string Create9610OrderForwardUrl =
|
||||||
|
"https://api.ideship.com/itfx/InterfaceForward/ForwardWithSubscribe?standardCode=create9610Order&supplierCode=BH";
|
||||||
|
|
||||||
|
private async Task<Customs9610DeclareResult> DownstreamForwardOneAsync(int id)
|
||||||
|
{
|
||||||
|
var header = await GetOwnedOrThrowAsync(id);
|
||||||
|
if (!string.Equals(header.Status, Customs9610StatusCodes.Pending, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
throw new BusinessException("仅待申报单据可预报下游");
|
||||||
|
}
|
||||||
|
|
||||||
|
var items = await ItemRepository.GetByHeaderIdAsync(header.Id);
|
||||||
|
if (items.Count == 0)
|
||||||
|
{
|
||||||
|
throw new BusinessException("申报商品不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateHeaderForDeclare(header);
|
||||||
|
|
||||||
|
var order = await OrderRepository.FirstOrDefaultAsync(x => x.Id == header.OrderId)
|
||||||
|
?? throw new BusinessException("关联运单不存在");
|
||||||
|
|
||||||
|
var creds = await CredentialResolver.ResolveAsync(order);
|
||||||
|
var body = BuildDeclareBody(header, items);
|
||||||
|
ItfxForwardResult forward;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
forward = await ItfxForwardClient.ForwardToAbsoluteUrlAsync(
|
||||||
|
Create9610OrderForwardUrl,
|
||||||
|
creds.AppKey,
|
||||||
|
creds.AppSecret,
|
||||||
|
body);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
header.FailReason = Truncate(ex.Message, 512);
|
||||||
|
header.UpdateTime = DateTime.Now;
|
||||||
|
await HeaderRepository.UpdateAsync(header);
|
||||||
|
return new Customs9610DeclareResult
|
||||||
|
{
|
||||||
|
Id = header.Id,
|
||||||
|
Success = false,
|
||||||
|
Message = header.FailReason ?? "调用 API 中心失败",
|
||||||
|
Status = header.Status,
|
||||||
|
ServiceNo = header.ServiceNo,
|
||||||
|
ClientNo = header.ClientNo,
|
||||||
|
Url = Create9610OrderForwardUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!forward.Success)
|
||||||
|
{
|
||||||
|
var reason = ItfxForwardResultEvaluator.BuildFailReason(
|
||||||
|
forward.StatusCode,
|
||||||
|
forward.ResponseBody,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
header.FailReason = Truncate(reason, 512);
|
||||||
|
header.UpdateTime = DateTime.Now;
|
||||||
|
await HeaderRepository.UpdateAsync(header);
|
||||||
|
return new Customs9610DeclareResult
|
||||||
|
{
|
||||||
|
Id = header.Id,
|
||||||
|
Success = false,
|
||||||
|
Message = header.FailReason ?? "预报下游失败",
|
||||||
|
Status = header.Status,
|
||||||
|
ServiceNo = header.ServiceNo,
|
||||||
|
ClientNo = header.ClientNo,
|
||||||
|
HttpStatusCode = forward.StatusCode,
|
||||||
|
ResponseBody = forward.ResponseBody,
|
||||||
|
Url = forward.Url,
|
||||||
|
RequestJson = forward.RequestJson,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
TryParseDeclareResponse(forward.ResponseBody, out var customsOrderNo, out var downstreamRef);
|
||||||
|
header.Status = Customs9610StatusCodes.Declared;
|
||||||
|
header.CustomsOrderNo = Truncate(customsOrderNo, 32) ?? header.CustomsOrderNo;
|
||||||
|
header.DownstreamRefNo = Truncate(downstreamRef, 32) ?? header.DownstreamRefNo;
|
||||||
|
header.DeclareTime = DateTime.Now;
|
||||||
|
header.FailReason = null;
|
||||||
|
header.UpdateTime = DateTime.Now;
|
||||||
|
await HeaderRepository.UpdateAsync(header);
|
||||||
|
|
||||||
|
return new Customs9610DeclareResult
|
||||||
|
{
|
||||||
|
Id = header.Id,
|
||||||
|
Success = true,
|
||||||
|
Message = "预报下游成功",
|
||||||
|
CustomsOrderNo = header.CustomsOrderNo,
|
||||||
|
Status = header.Status,
|
||||||
|
ServiceNo = header.ServiceNo,
|
||||||
|
ClientNo = header.ClientNo,
|
||||||
|
HttpStatusCode = forward.StatusCode,
|
||||||
|
ResponseBody = forward.ResponseBody,
|
||||||
|
Url = forward.Url,
|
||||||
|
RequestJson = forward.RequestJson,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Customs9610DeclareResult> FetchManifestOneAsync(int id)
|
private async Task<Customs9610DeclareResult> FetchManifestOneAsync(int id)
|
||||||
|
|||||||
@ -119,7 +119,9 @@ public class Customs9610OrderWriter : IScopedDependency
|
|||||||
{
|
{
|
||||||
var itemName = FirstNonEmpty(d.CnName, d.EnName) ?? string.Empty;
|
var itemName = FirstNonEmpty(d.CnName, d.EnName) ?? string.Empty;
|
||||||
var sku = FirstNonEmpty(d.Sku, $"ITEM{sort + 1}")!;
|
var sku = FirstNonEmpty(d.Sku, $"ITEM{sort + 1}")!;
|
||||||
var declareElement = JoinNonEmpty(" ", d.Model, d.Specifications, d.Attributes, d.Material);
|
var declareElement = FirstNonEmpty(
|
||||||
|
d.DeclareElement,
|
||||||
|
JoinNonEmpty(" ", d.Model, d.Specifications, d.Attributes, d.Material));
|
||||||
await _itemRepository.InsertAsync(new Customs9610OrderItem
|
await _itemRepository.InsertAsync(new Customs9610OrderItem
|
||||||
{
|
{
|
||||||
Customs9610OrderId = header.Id,
|
Customs9610OrderId = header.Id,
|
||||||
|
|||||||
@ -198,6 +198,7 @@ public static class AutoTriggerFormulaMeta
|
|||||||
yield return ("HS编码", "t_order_declaration", "HsCode", FormulaValueType.String, false);
|
yield return ("HS编码", "t_order_declaration", "HsCode", FormulaValueType.String, false);
|
||||||
yield return ("进口HS编码", "t_order_declaration", "ImHsCode", FormulaValueType.String, false);
|
yield return ("进口HS编码", "t_order_declaration", "ImHsCode", FormulaValueType.String, false);
|
||||||
yield return ("出口HS编码", "t_order_declaration", "ExHsCode", FormulaValueType.String, false);
|
yield return ("出口HS编码", "t_order_declaration", "ExHsCode", FormulaValueType.String, false);
|
||||||
|
yield return ("出口申报要素", "t_order_declaration", "DeclareElement", FormulaValueType.String, false);
|
||||||
yield return ("申报类别", "t_order_declaration", "Category", FormulaValueType.String, false);
|
yield return ("申报类别", "t_order_declaration", "Category", FormulaValueType.String, false);
|
||||||
yield return ("品牌", "t_order_declaration", "Brand", FormulaValueType.String, false);
|
yield return ("品牌", "t_order_declaration", "Brand", FormulaValueType.String, false);
|
||||||
yield return ("品牌类型", "t_order_declaration", "BrandType", FormulaValueType.String, false);
|
yield return ("品牌类型", "t_order_declaration", "BrandType", FormulaValueType.String, false);
|
||||||
|
|||||||
@ -759,6 +759,7 @@ public partial class OrderService
|
|||||||
HsCode = x.ExHsCode ?? x.ImHsCode ?? x.HsCode,
|
HsCode = x.ExHsCode ?? x.ImHsCode ?? x.HsCode,
|
||||||
ImHsCode = x.ImHsCode ?? x.HsCode,
|
ImHsCode = x.ImHsCode ?? x.HsCode,
|
||||||
ExHsCode = x.ExHsCode ?? x.HsCode,
|
ExHsCode = x.ExHsCode ?? x.HsCode,
|
||||||
|
DeclareElement = x.DeclareElement,
|
||||||
SkuImage = FileStorage.GetPublicUrl(x.SkuImage),
|
SkuImage = FileStorage.GetPublicUrl(x.SkuImage),
|
||||||
Category = x.Category,
|
Category = x.Category,
|
||||||
Brand = x.Brand,
|
Brand = x.Brand,
|
||||||
|
|||||||
@ -1128,6 +1128,7 @@ public partial class OrderService
|
|||||||
HsCode = x.ExHsCode ?? x.ImHsCode,
|
HsCode = x.ExHsCode ?? x.ImHsCode,
|
||||||
ImHsCode = x.ImHsCode,
|
ImHsCode = x.ImHsCode,
|
||||||
ExHsCode = x.ExHsCode ?? x.ImHsCode,
|
ExHsCode = x.ExHsCode ?? x.ImHsCode,
|
||||||
|
DeclareElement = x.DeclareElement,
|
||||||
SkuImage = FileStorage.ToStorageKey(x.SkuImage),
|
SkuImage = FileStorage.ToStorageKey(x.SkuImage),
|
||||||
Category = x.Category,
|
Category = x.Category,
|
||||||
Brand = x.Brand,
|
Brand = x.Brand,
|
||||||
|
|||||||
@ -2012,6 +2012,7 @@ public partial class OrderService
|
|||||||
HsCode = x.ExHsCode ?? x.ImHsCode,
|
HsCode = x.ExHsCode ?? x.ImHsCode,
|
||||||
ImHsCode = x.ImHsCode,
|
ImHsCode = x.ImHsCode,
|
||||||
ExHsCode = x.ExHsCode,
|
ExHsCode = x.ExHsCode,
|
||||||
|
DeclareElement = x.DeclareElement,
|
||||||
SkuImage = FileStorage.ToStorageKey(x.SkuImage),
|
SkuImage = FileStorage.ToStorageKey(x.SkuImage),
|
||||||
Category = x.Category,
|
Category = x.Category,
|
||||||
Brand = x.Brand,
|
Brand = x.Brand,
|
||||||
|
|||||||
@ -121,6 +121,7 @@ public partial class WarehouseService
|
|||||||
entity.UnitPrice = input.UnitPrice;
|
entity.UnitPrice = input.UnitPrice;
|
||||||
entity.ExHsCode = string.IsNullOrWhiteSpace(input.ExHsCode) ? null : input.ExHsCode.Trim();
|
entity.ExHsCode = string.IsNullOrWhiteSpace(input.ExHsCode) ? null : input.ExHsCode.Trim();
|
||||||
entity.ImHsCode = string.IsNullOrWhiteSpace(input.ImHsCode) ? null : input.ImHsCode.Trim();
|
entity.ImHsCode = string.IsNullOrWhiteSpace(input.ImHsCode) ? null : input.ImHsCode.Trim();
|
||||||
|
entity.DeclareElement = string.IsNullOrWhiteSpace(input.DeclareElement) ? null : input.DeclareElement.Trim();
|
||||||
entity.WeightG = input.WeightG;
|
entity.WeightG = input.WeightG;
|
||||||
entity.LengthCm = input.LengthCm;
|
entity.LengthCm = input.LengthCm;
|
||||||
entity.WidthCm = input.WidthCm;
|
entity.WidthCm = input.WidthCm;
|
||||||
@ -230,6 +231,7 @@ public partial class WarehouseService
|
|||||||
UnitPrice = entity.UnitPrice,
|
UnitPrice = entity.UnitPrice,
|
||||||
ExHsCode = entity.ExHsCode,
|
ExHsCode = entity.ExHsCode,
|
||||||
ImHsCode = entity.ImHsCode,
|
ImHsCode = entity.ImHsCode,
|
||||||
|
DeclareElement = entity.DeclareElement,
|
||||||
WeightG = entity.WeightG,
|
WeightG = entity.WeightG,
|
||||||
LengthCm = entity.LengthCm,
|
LengthCm = entity.LengthCm,
|
||||||
WidthCm = entity.WidthCm,
|
WidthCm = entity.WidthCm,
|
||||||
@ -251,6 +253,7 @@ public partial class WarehouseService
|
|||||||
UnitPrice = entity.UnitPrice,
|
UnitPrice = entity.UnitPrice,
|
||||||
ExHsCode = entity.ExHsCode,
|
ExHsCode = entity.ExHsCode,
|
||||||
ImHsCode = entity.ImHsCode,
|
ImHsCode = entity.ImHsCode,
|
||||||
|
DeclareElement = entity.DeclareElement,
|
||||||
WeightG = entity.WeightG,
|
WeightG = entity.WeightG,
|
||||||
LengthCm = entity.LengthCm,
|
LengthCm = entity.LengthCm,
|
||||||
WidthCm = entity.WidthCm,
|
WidthCm = entity.WidthCm,
|
||||||
|
|||||||
@ -199,6 +199,7 @@ public static class OrderDownstreamCreateOneBodyBuilder
|
|||||||
Weight = x.Weight,
|
Weight = x.Weight,
|
||||||
ImHsCode = x.ImHsCode,
|
ImHsCode = x.ImHsCode,
|
||||||
ExHsCode = x.ExHsCode ?? x.HsCode,
|
ExHsCode = x.ExHsCode ?? x.HsCode,
|
||||||
|
DeclareElement = x.DeclareElement,
|
||||||
SkuImage = fileStorage?.GetPublicUrl(x.SkuImage) ?? x.SkuImage,
|
SkuImage = fileStorage?.GetPublicUrl(x.SkuImage) ?? x.SkuImage,
|
||||||
Category = x.Category,
|
Category = x.Category,
|
||||||
Brand = x.Brand,
|
Brand = x.Brand,
|
||||||
|
|||||||
@ -0,0 +1,58 @@
|
|||||||
|
using Oms.Domain.Shared;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace Oms.Domain.CustomersAggregate.Entities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 客户出口资质备案。
|
||||||
|
/// </summary>
|
||||||
|
[SugarTable("t_customer_export_qualification")]
|
||||||
|
public class CustomerExportQualification : OmsAuditedAggregateRoot
|
||||||
|
{
|
||||||
|
public int CustomerId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 企业名称。
|
||||||
|
/// </summary>
|
||||||
|
public string CompanyName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 企业社会信用代码。
|
||||||
|
/// </summary>
|
||||||
|
public string SocialCreditCode { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 境内发货人。
|
||||||
|
/// </summary>
|
||||||
|
public string DomesticConsignor { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 境内发货人海关代码。
|
||||||
|
/// </summary>
|
||||||
|
public string? DomesticConsignorCustomsCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生产销售单位。
|
||||||
|
/// </summary>
|
||||||
|
public string ProducerName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生产销售单位海关代码。
|
||||||
|
/// </summary>
|
||||||
|
public string? ProducerCustomsCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 备案海关港口地。
|
||||||
|
/// </summary>
|
||||||
|
public string? CustomsPort { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否默认:同客户仅一条为默认。
|
||||||
|
/// </summary>
|
||||||
|
public byte IsDefault { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 备注。
|
||||||
|
/// </summary>
|
||||||
|
public string? Remark { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using Fake.Domain.Repositories;
|
||||||
|
using Oms.Domain.CustomersAggregate.Entities;
|
||||||
|
|
||||||
|
namespace Oms.Domain.CustomersAggregate.Repositories;
|
||||||
|
|
||||||
|
public interface ICustomerExportQualificationRepository : IRepository<CustomerExportQualification>
|
||||||
|
{
|
||||||
|
Task<CustomerExportQualification?> GetOwnedAsync(
|
||||||
|
int id,
|
||||||
|
int customerId,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task ClearDefaultAsync(
|
||||||
|
int customerId,
|
||||||
|
int? excludeId = null,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
@ -32,6 +32,11 @@ public class OrderDeclaration : OmsAuditedEntity
|
|||||||
|
|
||||||
public string? ExHsCode { get; set; }
|
public string? ExHsCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口申报要素。
|
||||||
|
/// </summary>
|
||||||
|
public string? DeclareElement { get; set; }
|
||||||
|
|
||||||
public string? SkuImage { get; set; }
|
public string? SkuImage { get; set; }
|
||||||
|
|
||||||
public string? Category { get; set; }
|
public string? Category { get; set; }
|
||||||
|
|||||||
@ -22,6 +22,11 @@ public class CSku : OmsAuditedAggregateRoot
|
|||||||
|
|
||||||
public string? ImHsCode { get; set; }
|
public string? ImHsCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 出口申报要素。
|
||||||
|
/// </summary>
|
||||||
|
public string? DeclareElement { get; set; }
|
||||||
|
|
||||||
public decimal? WeightG { get; set; }
|
public decimal? WeightG { get; set; }
|
||||||
|
|
||||||
public decimal? LengthCm { get; set; }
|
public decimal? LengthCm { get; set; }
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
using Fake.DependencyInjection;
|
||||||
|
using Oms.Domain.CustomersAggregate.Entities;
|
||||||
|
using Oms.Domain.CustomersAggregate.Repositories;
|
||||||
|
using Oms.SqlSugarCore.Repositories;
|
||||||
|
|
||||||
|
namespace Oms.SqlSugarCore.Customers;
|
||||||
|
|
||||||
|
public class CustomerExportQualificationRepository
|
||||||
|
: OmsSqlSugarRepository<CustomerExportQualification>,
|
||||||
|
ICustomerExportQualificationRepository,
|
||||||
|
IScopedDependency
|
||||||
|
{
|
||||||
|
public Task<CustomerExportQualification?> GetOwnedAsync(
|
||||||
|
int id,
|
||||||
|
int customerId,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return FirstOrDefaultAsync(x => x.Id == id && x.CustomerId == customerId, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ClearDefaultAsync(
|
||||||
|
int customerId,
|
||||||
|
int? excludeId = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var hasExcludeId = excludeId.HasValue;
|
||||||
|
var excludeIdValue = excludeId.GetValueOrDefault();
|
||||||
|
var list = await GetListAsync(
|
||||||
|
x => x.CustomerId == customerId
|
||||||
|
&& x.IsDefault == 1
|
||||||
|
&& (!hasExcludeId || x.Id != excludeIdValue),
|
||||||
|
cancellationToken: cancellationToken);
|
||||||
|
if (list.Count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
item.IsDefault = 0;
|
||||||
|
await UpdateAsync(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user