首页 新闻 会员 周边 捐助

海外网购订单,要求每张订单不得超过1000元,允许拆单,用了穷举算法,从而导致拆单性能不好。

0
悬赏园豆:10 [待解决问题]

一、需了解的知识:

通关关税
海购通过正规的清关渠道进行清关,一切遵照海关相关法律、法规进行操作,并且尽量保障清关时效

1.目前对于购买跨境电商平台上的商品,国家的相关政策是怎样的?
以“个人自用、合理数量”为原则,参照《海关总署公告2010年第43号(关于调整进出境个人邮递物品管理措施有关事宜)》要求,个人寄自或寄往港、澳、台地区的物品,每次限值为800元人民币;寄自或寄往其它国家和地区的物品,每次限值为1000元人民币。个人邮寄进出境物品超出规定限值的,应办理退运手续或者按照货物规定办理通关手续。但邮包内仅有一件物品且不可分割的,虽超出规定限值,经海关审核确属个人自用的,可以按照个人物品规定办理通关手续。
2.购买海购进口的商品是否需要缴税?
根据海关总署规定,购买跨境平台商品,以电子订单的实际销售价格作为完税价格(征税基数),参照行邮税税率计征进口税税款,应征税额在人民币:
50元(含50元)以下的,海关予以免征,超过50元税额,全额征缴。
比如一包纸尿裤销售价格130元,进口税税率10%,那么税额就是13元,低于50元,不用缴税;
但如果一次购买4包,税额52元,需要缴纳52元进口税。
3.如果产生进口税,是否需要自己亲自缴纳?
在海购上,消费者是通过委托海购代缴的形式来缴纳关税的。消费者在订单提交时根据订单内商品的金额和对应的税率缴纳相应的关税,和订单商品金额运费等一并付给海购,无需自己再到相应的海关部门单独缴纳,海购将会根据顾客的订单统一向海关缴纳关税。
4.我在海购上购买的商品的关税是如何核算的?
在海购上购买的商品:
商品关税 =完税价格*行邮税率;
完税价格=商品单价*数量-活动优惠金额-优惠券优惠的金额;
如果订单商品的关税价格之和小于等于50元,关税免征。如果订单商品的关税价格之和大于50元,则需要缴纳关税。

例如,如果订单中包含A商品2件,单价100元,B商品2件,单价300元。A商品参加活动优惠了30元,B商品参加活动优惠了10元,使用优惠券后A商品又优惠了10元。A商品适用行邮税率10%,B商品适用行邮税率10%。
那么,
A商品的关税=完税价格*行邮税率=(100*2-30-10)*10%=16
B商品的关税=完税价格*行邮税率=(300*2-10)*10%=59
则订单需要缴纳的关税=A商品的关税+B商品的关税=75

二、海外网购订单,要求每张订单不得超过1000元,允许拆单,单件商品无此限制。为了避税,就要由软件系统自动拆。

拆单的罗辑是这样的:

0、先按供货商分拆
1、再按商品运费模板分拆
2、订单总额不超过1000,且税费不大于50,无需拆单
3、单品税费大于50的商品可以组成一个单,金额不超过1000
4、所有单价大于1000的商品形成一个单独的订单
5、剩下的产品项,金额都小于1000,遍历配对组合。
    a、凡是与所有其他项两两配对后都超过1000的,拆单。
    b、凡是与所有其他项两两配对后都超过50的,拆单。
    c、订单中只有一个商品的,按金额(1000)或税额(50)拆单
    d、否则保留最接近1000的配对,视作一个组合项,递归本步骤,直到没有可以拆分。

现在的问题是:拆单很慢,性能不好,这个穷举方法(GetChildCollections具体如下)最影响性能,哪位大师有比较好的方法和思路?

主要代码如下:

/// <summary>
/// 找到满足条件的订单大集合
/// </summary>
/// <param name="lineItemInfoGroups">订单大集合</param>
/// <param name="ListLineItemInfo">订单集合</param>
public static void GetLineItemInfoGroups(ref List<List<LineItemInfo>> lineItemInfoGroups, List<LineItemInfo> ListLineItemInfo) //拆分orderItem
{
if (ListLineItemInfo == null || ListLineItemInfo.Count < 1)
{
return;
}
if (ListLineItemInfo.Count == 1)
{
lineItemInfoGroups.Add(ListLineItemInfo);
return;
}
LineItemInfo tempLineItemInfo = null;
List<structTax> structTax = new List<structTax>();
//降低一个复杂度,如果原来是n的n次方的复杂度的话,-1就是n的n-1次方了
tempLineItemInfo = ListLineItemInfo[0];
ListLineItemInfo.RemoveAt(0);


 List<List<LineItemInfo>> ListLineItemInfocollections = GetChildCollections(ListLineItemInfo);//穷举
 

int k = 0;
ListLineItemInfo.Add(tempLineItemInfo);
foreach (List<LineItemInfo> item in ListLineItemInfocollections)
{
item.Add(tempLineItemInfo);
decimal tmpTax = 0m;
decimal productTotal = 0m;
item.ForEach(a => { tmpTax += a.TaxRate * a.ItemAdjustedPrice; productTotal += a.Quantity * a.ItemAdjustedPrice; });
structTax.Add(new structTax(k, 50 - tmpTax, item.Count, productTotal));
k++;
}
//分组的id,有10000个组合,每一个组合做了个编号
var groupId = 0;
List<structTax> conformTax = (from s
in structTax
where s.tax >= 0 && s.tax < 50 && s.productTotal <= 1000
select s).OrderBy(a => a.tax).ThenByDescending(a => a.itemCount).ToList();

if (conformTax != null && conformTax.Count > 0)//理想组合,税费<50&&商品总额<=1000
{
groupId = conformTax.FirstOrDefault().index;
lineItemInfoGroups.Add(ListLineItemInfocollections[groupId]);
ListLineItemInfocollections[groupId].ForEach(a => ListLineItemInfo.Remove(a));
}
else//商品税费大于50||商品税率为0||商品总额>1000
{
if (ListLineItemInfo.Count > 0)
{
List<structTax> badTax = (from s in structTax where s.productTotal <= 1000 select s).OrderByDescending(a => a.itemCount).ToList();
if (badTax != null && badTax.Count > 0)//税率>50 && 商品总额<=1000
{
groupId = badTax.FirstOrDefault().index;
lineItemInfoGroups.Add(ListLineItemInfocollections[groupId]);
//找了合适的组合了,就把这个组合内的所有商品从大集合中去掉
ListLineItemInfocollections[groupId].ForEach(a => ListLineItemInfo.Remove(a));
}
else//税率>50 &&商品总额>1000 (合适的组合)
{
foreach (LineItemInfo lastItem in ListLineItemInfo)
{
List<LineItemInfo> lastGroupLineItemInfo = new List<LineItemInfo>() { lastItem };
lineItemInfoGroups.Add(lastGroupLineItemInfo);
}
ListLineItemInfo = null;
}
}
}

//递归调用
GetLineItemInfoGroups(ref lineItemInfoGroups, ListLineItemInfo);
}

/// <summary>
/// 穷举所有组合
/// </summary>
/// <param name="list">订单大集合</param>
/// <returns></returns>
public static List<List<LineItemInfo>> GetChildCollections(List<LineItemInfo> list)
{
//<< 左移相当于乘,左移一位相当于乘2 demo:var t = 1 << 2;t= 4,最大为2的30次方法,就是list.Count最大为30,否则就会报错
var lic = Enumerable.Range(0, 1 << list.Count);
var subsets = from m in lic
select (from i in lic
where (m & (1 << i)) != 0
select list[i]).ToList();
return subsets.ToList();
}

Hamilton Tan的主页 Hamilton Tan | 初学一级 | 园豆:167
提问于:2015-09-07 22:57
< >
分享
所有回答(2)
0

如果只是两两配对,为什么不试用SQL INNER JOIN?

XiaoFaye | 园豆:3087 (老鸟四级) | 2015-09-08 06:55
0

算法优化的话就是先排序。以金额和税排序,具体算法想来也还是挺复杂的。

有序数组的话,就不需要整个遍历了。而且还可以通过查找算法快速找到合适的拆单点,

吴瑞祥 | 园豆:29449 (高人七级) | 2015-09-08 09:11
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册