def gen_new_stock_sale(user): """获取""" BatchStockSale.objects.filter(status__in=[0, 1]).update(status=2) if BatchStockSale.objects.filter(status__in=[0, 1]).exists(): raise Exception(u'此前的批次尚未处理完,请先关闭此前的批次') batch = BatchStockSale.gen(user) res = {} for stat in SkuStock.get_auto_sale_stock().select_related('product'): if stat.product_id not in res: res[stat.product_id] = StockSale( sale_product_id=stat.product.sale_product if stat.product.sale_product else None, product=stat.product, batch=batch, day_batch_num=0, quantity=stat.realtime_quantity, sku_num=1, sku_detail={stat.sku_id, stat.realtime_quantity}, location=stat.product.get_district_info() ) else: res[stat.product_id].quantity += stat.realtime_quantity res[stat.product_id].sku_num += 1 res[stat.sku_detail][stat.sku_id] = stat.realtime_quantity StockSale.objects.bulk_create(res.values()) product_ids = res.keys() batch.status = 1 batch.sku_total = SkuStock.get_auto_sale_stock().filter(product_id__in=product_ids).count() batch.stock_total = SkuStock.get_auto_sale_stock().filter(product_id__in=product_ids).aggregate( s=Sum(F('history_quantity') + F('inbound_quantity') + F('adjust_quantity') + F('return_quantity') - F('post_num')) - F('rg_quantity')).get('s', 0) batch.product_total = len(product_ids) batch.total = len(batch.stocksale_set.exclude(sale_product=None).values('sale_product_id').distinct()) batch.save() return batch
def add_into_stock(self): if not self.sku_id: logger.warn({ 'action': "add_into_stock", 'info': 'Sku_id is not exist' }) return if not self.can_reuse: return from shopback.items.models import SkuStock SkuStock.add_return_quantity(self.sku_id, self.num, stat=True) SkuStock.get_by_sku(self.sku_id).assign()
def begin(self, request, pk=None): product_ids = request.GET.get('product_ids', '') skus_dict = json.loads(request.GET.get('skus', '{}')) or {} sku_ids = skus_dict.keys() user = request.user orderDrAll = OrderDraft.objects.all().filter(buyer_name=user) if sku_ids: skus = ProductSku.objects.filter( id__in=sku_ids).select_related('product') elif product_ids: skus = ProductSku.objects.filter( product_id__in=product_ids).select_related('product') else: skus = [] product_dicts = {} for sku in skus: if sku.product_id in product_dicts: product_dict = product_dicts.get(sku.product_id) else: product_dict = model_to_dict(sku.product) product_dict['prod_skus'] = [] product_dicts[sku.product_id] = product_dict sku_dict = model_to_dict(sku) sku_dict['name'] = sku.name sku_dict['need_order'] = skus_dict.get(str(sku.id), 1) sku_dict['wait_post_num'] = SkuStock.get_by_sku( sku.id).wait_post_num product_dict['prod_skus'].append(sku_dict) productres = product_dicts.values() return render(request, 'dinghuo/purchase/purchase.html', { "productRestult": productres, "drafts": orderDrAll })
def queryset(self, request, queryset): supplier_name = self.value() from shopback.items.models import SkuStock from pms.supplier.models import SaleSupplier supplier = SaleSupplier.objects.filter( supplier_name=supplier_name).first() if supplier_name else None if not supplier: return queryset else: return queryset.filter( product_id__in=SkuStock.filter_by_supplier(supplier.id))
def task_refundproduct_update_productskustats_return_quantity(sku_id): from shopback.refunds.models import RefundProduct logger.info("%s -sku_id:%s" % (get_cur_info(), sku_id)) sum_res = RefundProduct.objects.filter(sku_id=sku_id, created__gt=SkuStock.PRODUCT_SKU_STATS_COMMIT_TIME, can_reuse=True) \ .aggregate(total=Sum('num')) total = sum_res["total"] or 0 stat = SkuStock.get_by_sku(sku_id) if stat.return_quantity != total: stat.return_quantity = total stat.save(update_fields=['return_quantity']) stat.assign()
def gen_new_activity(creator, cnt=20): """ 获取100个sale_order, 生成新活动。时间为最后次专题活动时间或批次生成时间 """ batch_id = BatchStockSale.objects.order_by('-id').first().id old_day_batch_num = StockSale.get_max_day_batch_num(batch_id) new_day_batch_num = old_day_batch_num + 1 new_expected_time = ActivityStockSale.get_begin_time() sale_product_ids = [s['sale_product_id'] for s in StockSale.objects.filter(batch_id=batch_id, day_batch_num=0).values( 'sale_product_id').distinct()[0:cnt]] product_total = StockSale.objects.filter(sale_product_id__in=sale_product_ids, batch_id=batch_id).count() product_ids = [s['product_id'] for s in StockSale.objects.filter(sale_product_id__in=sale_product_ids, batch_id=batch_id).values('product_id')] sku_total = SkuStock.get_auto_sale_stock().filter(product_id__in=product_ids).count() # self.history_quantity + self.inbound_quantity + self.adjust_quantity + self.return_quantity - self.post_num - self.rg_quantity stock_total = SkuStock.get_auto_sale_stock().filter(product_id__in=product_ids).aggregate( s=Sum(F('history_quantity') + F('inbound_quantity') + F('adjust_quantity') + F('return_quantity') - F('post_num')) - F('rg_quantity')).get('s', 0) ass = ActivityStockSale(batch_id=batch_id, day_batch_num=new_day_batch_num, onshelf_time=new_expected_time, offshelf_time=new_expected_time + datetime.timedelta(days=StockSale.INTERVAL), total=len(sale_product_ids), product_total=product_total, sku_total=sku_total, stock_total=stock_total, creator=creator ) ass.save() StockSale.objects.filter(sale_product_id__in=sale_product_ids, batch_id=batch_id, day_batch_num=0).update( day_batch_num=new_day_batch_num, activity=ass ) return ass.id
def task_saleorder_update_productskustats_waitingpay_num(sku_id): """ Recalculate and update post_num. """ from flashsale.pay.models import SaleOrder product_id = ProductSku.objects.get(id=sku_id).product.id waitingpay_num_res = SaleOrder.objects.filter( item_id=product_id, sku_id=sku_id, status=SaleOrder.WAIT_BUYER_PAY).aggregate(Sum('num')) total = waitingpay_num_res['num__sum'] or 0 stat = SkuStock.get_by_sku(sku_id) if stat.waitingpay_num != total: stat.waitingpay_num = total stat.save(update_fields=["waitingpay_num"])
def queryset(self, request, queryset): status_id = self.value() if not status_id: return queryset else: if status_id == '1': return queryset.filter( return_quantity__gt=F('sold_num') + F('rg_quantity') - F('history_quantity') - F('adjust_quantity') - F('inbound_quantity')) if status_id == '2': return queryset.filter( return_quantity=F('sold_num') + F('rg_quantity') - F('history_quantity') - F('adjust_quantity') - F('inbound_quantity')) if status_id == '3': return queryset.filter(id__in=SkuStock.redundancies())
def task_update_product_sku_stat_rg_quantity(sku_id): from shopback.dinghuo.models.purchase_return import RGDetail, ReturnGoods logger.info("%s -sku_id:%s" % (get_cur_info(), sku_id)) sum_res = RGDetail.objects.filter( skuid=sku_id, created__gte=SkuStock.PRODUCT_SKU_STATS_COMMIT_TIME, return_goods__status__in=[ ReturnGoods.DELIVER_RG, ReturnGoods.REFUND_RG, ReturnGoods.SUCCEED_RG ], type=RGDetail.TYPE_REFUND).aggregate(total=Sum('num')) total = sum_res["total"] or 0 stat = SkuStock.get_by_sku(sku_id) if stat.rg_quantity != total: stat.rg_quantity = total stat.save(update_fields=['rg_quantity']) stat.assign()
def task_orderdetail_update_productskustats_inbound_quantity(instance): """ Whenever we have products inbound, we update the inbound quantity. 0) OrderDetail arrival_time add db_index=True 1) we should build joint-index for (sku,arrival_time)? --Zifei 2016-04-18 """ from shopback.dinghuo.models import OrderDetail sku_id = instance.sku_id logger.info("%s -sku_id:%s" % (get_cur_info(), sku_id)) sum_res = OrderDetail.objects.filter(chichu_id=sku_id, arrival_time__gt=SkuStock.PRODUCT_SKU_STATS_COMMIT_TIME) \ .aggregate(total=Sum('arrival_quantity')) total = sum_res["total"] or 0 stat = SkuStock.get_by_sku(sku_id) stat.inbound_quantity = total stat.save(update_fields=['inbound_quantity', 'modified']) stat.assign(orderlist=instance.orderlist)
def task_packageskuitem_update_productskustats(sku_id): """ 1) we added db_index=True for pay_time in packageskuitem; 2) we should built joint-index for (sku_id, assign_status,pay_time)? -- Zifei 2016-04-18 """ from shopback.trades.models import PackageSkuItem logger.info("%s -sku_id:%s" % (get_cur_info(), sku_id)) sum_res = PackageSkuItem.objects.filter(sku_id=sku_id, pay_time__gt=SkuStock.PRODUCT_SKU_STATS_COMMIT_TIME, type=0). \ exclude(assign_status=PackageSkuItem.CANCELED).values("assign_status").annotate(total=Sum('num')) wait_assign_num, assign_num, post_num, third_assign_num = 0, 0, 0, 0 for entry in sum_res: if entry["assign_status"] == PackageSkuItem.NOT_ASSIGNED: wait_assign_num = entry["total"] elif entry["assign_status"] == PackageSkuItem.ASSIGNED: assign_num = entry["total"] elif entry["assign_status"] == PackageSkuItem.FINISHED: post_num = entry["total"] elif entry['assign_status'] == PackageSkuItem.VIRTUAL_ASSIGNED: third_assign_num = entry["total"] sold_num = wait_assign_num + assign_num + post_num + third_assign_num params = { "sold_num": sold_num, "assign_num": assign_num, "post_num": post_num } klogger = logging.getLogger('service') klogger.info({ 'action': 'skustat.pstat.task_packageskuitem_update_productskustats', 'sku_id': sku_id, 'params': json.dumps(params), }) stat = SkuStock.get_by_sku(sku_id) update_fields = [] for k, v in params.iteritems(): if hasattr(stat, k): if getattr(stat, k) != v: setattr(stat, k, v) update_fields.append(k) if update_fields: update_fields.append('modified') stat.save(update_fields=update_fields)
def sync_stock_by_adjust(self, data): """ 更新实时库存数据,如果数据不与skustock的数据一致,则将原记录/新记录/skustock数据都保存到stockadjust当中。 :param data: :return: """ from shopback.warehouse.models import StockAdjust, constants from shopback.items.models import SkuStock, ProductSku, InferiorSkuStats ori_dict = self.to_dict() self.pull_bad_qty = data['bad_qty'] self.pull_good_available_qty = data['good_available_qty'] self.pull_good_lock_qty = data['good_lock_qty'] self.last_pull_time = datetime.datetime.now() self.save() now_dict = self.to_dict() sku = ProductSku.get_by_outer_id(self.sku_code) stock = SkuStock.get_by_sku(sku.id) inferior_sku_stats = InferiorSkuStats.get_by_sku(sku.id) # 正品数不同 if self.now_quantity != stock.realtime_quantity: note = '%s实时库存不同,我方%d,对方%d。本次新数据%s~我仓数据%s~原数据%s' %\ (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), self.now_quantity, stock.realtime_quantity, json.dumps(ori_dict, cls=CJsonEncoder), json.dumps(stock.to_dict(), cls=CJsonEncoder), json.dumps(now_dict, cls=CJsonEncoder)) delta = self.now_quantity - stock.realtime_quantity StockAdjust.create(None, sku.id, delta, constants.WARE_NONE, inferior=False, note=note) # 次品数不同 elif self.now_bad_quantity != inferior_sku_stats.realtime_quantity: note = '%s次品库存不同,我方%d,对方%d。本次对方数据%s~我方数据%s~上次对方数据%s' %\ (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), self.now_quantity, inferior_sku_stats.realtime_quantity, json.dumps(ori_dict, cls=CJsonEncoder), json.dumps(now_dict, cls=CJsonEncoder), json.dumps(inferior_sku_stats.to_dict(), cls=CJsonEncoder)) delta = self.now_bad_quantity - inferior_sku_stats.realtime_quantity StockAdjust.create(None, sku.id, delta, constants.WARE_NONE, inferior=True, note=note)
def task_shoppingcart_update_productskustats_shoppingcart_num(sku_id): """ Recalculate and update shoppingcart_num. """ from flashsale.pay.models import ShoppingCart try: # product_id = ProductSku.objects.get(id=sku_id).product.id shoppingcart_num_res = ShoppingCart.objects.filter( sku_id=sku_id, status=ShoppingCart.NORMAL).aggregate(Sum('num')) total = shoppingcart_num_res['num__sum'] or 0 stat = SkuStock.get_by_sku(sku_id) if stat.shoppingcart_num != total: stat.shoppingcart_num = total stat.save(update_fields=["shoppingcart_num"]) except IntegrityError as exc: logger.warn( "IntegrityError - productskustat/shoppingcart_num | sku_id: %s, shoppingcart_num: %s" % (sku_id, total)) raise task_shoppingcart_update_productskustats_shoppingcart_num.retry( exc=exc)
def task_product_upshelf_update_productskusalestats(sku_id): """ Recalculate and update init_waitassign_num,sale_start_time. """ from shopback.items.models import ProductSku, SkuStock, \ ProductSkuSaleStats, gen_productsksalestats_unikey sku = ProductSku.objects.get(id=sku_id) product_id = sku.product_id sku_stats = SkuStock.get_by_sku(sku_id) wait_assign_num = sku_stats.wait_assign_num stats_uni_key = gen_productsksalestats_unikey(sku_id) stats = ProductSkuSaleStats.objects.filter(uni_key=stats_uni_key, sku_id=sku_id) if stats.count() == 0: model_product = sku.product.get_product_model() try: stat = ProductSkuSaleStats( uni_key=stats_uni_key, sku_id=sku_id, product_id=product_id, init_waitassign_num=wait_assign_num, sale_start_time=model_product.onshelf_time, sale_end_time=model_product.offshelf_time) stat.save() except IntegrityError as exc: logger.warn( "IntegrityError - productskusalestat/init_waitassign_num | sku_id: %s, init_waitassign_num: %s" % (sku_id, wait_assign_num)) raise task_product_upshelf_update_productskusalestats.retry( exc=exc) else: logger.warn( "RepeatUpshelf- productskusalestat/init_waitassign_num | sku_id: %s, init_waitassign_num: %s" % (sku_id, wait_assign_num))
def update_productskustats_adjust_num(sender, instance, created, **kwargs): if instance.status == 0: from shopback.items.models import SkuStock, InferiorSkuStats from shopback.items.models import ProductSku if not instance.inferior: # adjust_quantity = StockAdjust.objects.filter(sku_id=instance.sku_id, inferior=False)\ # .aggregate(n=Sum('num')).get('n') or 0 # SkuStock.update_adjust_num(instance.sku_id, adjust_quantity) SkuStock.add_adjust_num(instance.sku_id, instance.num) else: adjust_quantity = StockAdjust.objects.filter(sku_id=instance.sku_id, inferior=True)\ .aggregate(n=Sum('num')).get('n') or 0 InferiorSkuStats.update_adjust_num(instance.sku_id, adjust_quantity) StockAdjust.objects.filter(id=instance.id).update(status=1) ProductSku.objects.filter(id=instance.sku_id).update( quantity=instance.sku.stat.realtime_quantity) if instance.num > 0: SkuStock.get_by_sku(instance.sku_id).assign() else: SkuStock.get_by_sku(instance.sku_id).relase_assign()
def task_productsku_create_productskustats(sku_id, product_id): from shopback.items.models import SkuStock stats = SkuStock.objects.filter(sku_id=sku_id) if stats.count() <= 0: stat = SkuStock(sku_id=sku_id, product_id=product_id) stat.save()
def get_sale_product_to_sale_cnt(): product_ids = [p['product_id'] for p in SkuStock.get_auto_sale_stock().values('product_id').distinct()] return len(Product.objects.filter(id__in=product_ids).values('sale_product').distinct())
def multi_create(self, request, *args, **kwargs): """ 新增库存商品 新增款式 { "qs_code": "", "products": [ { "remain_num": "1", "agent_price": "4", "cost": "2", "name": "\u82e6\u4e01\u8336", "std_sale_price": "3" }, { "remain_num": "1", "agent_price": "4", "cost": "2", "name": "\u5c71\u6942\u5e72", "std_sale_price": "3" }, { "remain_num": "1", "agent_price": "4", "cost": "2", "name": "\u8377\u53f6\u8336", "std_sale_price": "3" } ], "name": "", "sale_time": "", "category_id": "19", "memo": "", "head_img": "", "saleproduct_id": "", "qhby_code": "" } """ content = request.data creator = request.user saleproduct_id = content.get("saleproduct_id", "") products_data = content.get('products') saleproduct = SaleProduct.objects.filter(id=saleproduct_id).first() if not saleproduct: raise exceptions.APIException(u"选品ID错误") supplier = saleproduct.sale_supplier category_id = content.get("category_id", "") category_item = ProductCategory.objects.get(cid=category_id) category_maps = { 3: '3', 39: '3', 6: '6', 5: '9', 52: '5', 44: '7', 8: '8', 49: '4', 10: '1' } if category_maps.has_key(category_item.parent_cid): outer_id = category_maps.get(category_item.parent_cid) + str( category_item.cid) + "%05d" % supplier.id elif category_item.cid == 9: outer_id = "100" + "%05d" % supplier.id else: raise exceptions.APIException(u"请选择正确分类") saleways = content.get("saleways") teambuy = False if saleways and (2 in saleways or '2' in saleways): teambuy = True teambuy_price = int(content.get("teambuy_price")) count = Product.objects.filter( outer_id__startswith=outer_id).count() or 1 inner_outer_id = outer_id + "%03d" % count while True: product_ins = Product.objects.filter( outer_id__startswith=inner_outer_id).count() if not product_ins or count > 998: break count += 1 inner_outer_id = outer_id + "%03d" % count if len(inner_outer_id) > 12: raise exceptions.APIException(u"编码位数不能超出12位") try: extras = default_modelproduct_extras_tpl() extras.setdefault('properties', {}) for key, value in content.iteritems(): if key.startswith('property.'): name = key.replace('property.', '') extras['properties'].update({name: value}) is_flatten = False if len(products_data) == 1: skus_data = products_data[0].get('skus', []) if not skus_data or len(skus_data) == 1: is_flatten = True # TODO@meron 考虑到亲子装问题,支持同一saleproduct录入多个modelproduct with transaction.atomic(): model_pro = ModelProduct( name=content['name'], head_imgs=content['head_img'], salecategory=saleproduct.sale_category, saleproduct=saleproduct, is_flatten=is_flatten, lowest_agent_price=round( min([float(p['agent_price']) for p in products_data]), 2), lowest_std_sale_price=round( min([ float(p['std_sale_price']) for p in products_data ]), 2), extras=extras, ) if teambuy: model_pro.is_teambuy = True model_pro.teambuy_price = teambuy_price model_pro.save() log_action(creator.id, model_pro, ADDITION, u'新建一个modelproduct new') pro_count = 1 for color in content['products']: # product除第一个颜色外, 其余的颜色的outer_id末尾不能为1 if (pro_count % 10) == 1 and pro_count > 1: pro_count += 1 one_product = Product( name=content['name'] + "/" + color['name'], outer_id=inner_outer_id + str(pro_count), model_id=model_pro.id, sale_charger=creator.username, category=category_item, remain_num=color['remain_num'], cost=color['cost'], agent_price=color['agent_price'], std_sale_price=color['std_sale_price'], ware_by=supplier.ware_by, pic_path=content['head_img'], sale_product=saleproduct.id, is_flatten=is_flatten, ) one_product.save() log_action(creator.id, one_product, ADDITION, u'新建一个product_new') pro_count += 1 # one_product_detail = Productdetail( # product=one_product, material=material, # color=content.get("all_colors", ""), # wash_instructions=wash_instroduce, note=note # ) # one_product_detail.save() barcode = '%s%d' % (one_product.outer_id, 1) one_sku = ProductSku( outer_id=barcode, product=one_product, remain_num=color['remain_num'], cost=color['cost'], std_sale_price=color['std_sale_price'], agent_price=color['agent_price'], properties_name=color['name'], properties_alias=color['name'], barcode=barcode) one_sku.save() try: SkuStock.get_by_sku(one_sku.id) except Exception, exc: logger.error('product skustats: new_sku_id=%s, %s' % (one_sku.id, exc.message), exc_info=True) except Exception, exc: logger.error('%s' % exc or u'商品资料创建错误', exc_info=True) raise exceptions.APIException(u'出错了:%s' % exc)
def set_stock_inbound(self): from shopback.items.models import SkuStock sku_dict = self.get_sku_instock_dict() for sku in sku_dict: stock = SkuStock.get_by_sku(sku) stock.add_inbound_quantity(sku, sku_dict[sku])
def assign_sku(self): from shopback.items.models import SkuStock for idetail in self.details.all(): for r in idetail.records.all(): SkuStock.get_by_sku(idetail.sku_id).assign( orderlist=r.orderdetail.orderlist, again=False)
def task_productsku_update_productskustats(sku_id, product_id): stats = SkuStock.objects.filter(sku_id=sku_id) if not stats.exists(): stat = SkuStock(sku_id=sku_id, product_id=product_id) stat.save()
def task_add_shoppingcart_num(instance): stat = SkuStock.get_by_sku(instance.sku_id) SkuStock.objects.filter(sku_id=stat.sku_id).update( shoppingcart_num=F('shoppingcart_num') + instance.num) return close_timeout_carts_and_orders_reset_cart_num([instance.sku_id])