123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- # coding=utf-8
- from django.db.models import Sum,F
- from django.utils import timezone
- from apps.exceptions import CustomError
- from apps.goods.models import GoodsGodownEntry,GoodsGodownEntryDetail
- from apps.purchase.models import GodownEntry,GodownEntryDetail
- from apps.warehouse.models import WarehouseStock,WarehouseRecord,WarehouseStockRecord,WarehouseRecordDetail,WarehouseBackMap,Inventory,InventoryDetail
- from apps.product.models import ProductBase
- from apps.base import Formater
- class BizWarehouse():
- # 更新冗余字段
- @staticmethod
- def updateRedundant(warehouse_record):
- type = warehouse_record.type
- if type in (WarehouseRecord.CK_ZJ,WarehouseRecord.CK_XS,WarehouseRecord.CK_PK,WarehouseRecord.TL):
- BizWarehouse._updateDeliveredRedundant(warehouse_record)
- elif type == WarehouseRecord.TH:
- BizWarehouse._updateEntryBackRedundant(warehouse_record)
- @staticmethod
- def _updateDeliveredRedundant(warehouse_record):
- goods_entry_ids = []
- inventory_ids = []
- entry_ids = []
- rows = WarehouseRecordDetail.objects.filter(warehouse_record=warehouse_record)
- for row in rows:
- stock_record = row.warehouse_stock_record
- deliver_count = BizWarehouse._getDeliveredCount(stock_record)
- deliver_amount = deliver_count * stock_record.entry_price
- goods_entry_detail = GoodsGodownEntryDetail.objects.filter(stock_record=stock_record).first()
- inventory_detail = InventoryDetail.objects.filter(warehouse_stock_record=stock_record).first()
- entry_detail = GodownEntryDetail.objects.filter(stock_record=stock_record).first()
- if goods_entry_detail:
- goods_entry_detail.deliver_count = deliver_count
- goods_entry_detail.deliver_amount = deliver_amount
- goods_entry_detail.save()
- goods_entry_ids.append(goods_entry_detail.main_id)
- if inventory_detail:
- inventory_detail.deliver_count = deliver_count
- inventory_detail.deliver_amount = deliver_amount
- inventory_detail.save()
- inventory_ids.append(inventory_detail.main_id)
- if entry_detail:
- entry_detail.deliver_count = deliver_count
- entry_detail.deliver_amount = deliver_amount
- entry_detail.save()
- entry_ids.append(entry_detail.main_id)
- BizWarehouse._updateMainRedundant(goods_entry_ids,inventory_ids,entry_ids)
- @staticmethod
- def _updateEntryBackRedundant(warehouse_record):
- goods_entry_ids = []
- inventory_ids = []
- entry_ids = []
- rows = WarehouseRecordDetail.objects.filter(warehouse_record=warehouse_record)
- for row in rows:
- stock_record = row.warehouse_stock_record
- return_count = BizWarehouse._getEntryBackCount(stock_record)
- return_amount = return_count * stock_record.entry_price
- inventory_detail = InventoryDetail.objects.filter(warehouse_stock_record=stock_record).first()
- entry_detail = GodownEntryDetail.objects.filter(stock_record=stock_record).first()
- if inventory_detail:
- inventory_detail.return_count = return_count
- inventory_detail.return_amount = return_amount
- inventory_detail.save()
- inventory_ids.append(inventory_detail.main_id)
- if entry_detail:
- entry_detail.return_count = return_count
- entry_detail.return_amount = return_amount
- entry_detail.save()
- entry_ids.append(entry_detail.main_id)
- BizWarehouse._updateMainRedundant(goods_entry_ids, inventory_ids, entry_ids)
- @staticmethod
- def _getDeliveredCount(stock_record):
- count = 0
- deliver_types = (WarehouseRecord.CK_ZJ,WarehouseRecord.CK_XS,WarehouseRecord.CK_PK,WarehouseRecord.TL)
- sum_row = WarehouseRecordDetail.objects.filter(
- warehouse_stock_record=stock_record,
- warehouse_record__type__in=deliver_types
- ).aggregate(total_count=Sum('count'))
- if sum_row:
- count = sum_row['total_count'] or 0
- return -count
- @staticmethod
- def _getEntryBackCount(stock_record):
- count = 0
- sum_row = WarehouseRecordDetail.objects.filter(
- warehouse_stock_record=stock_record,
- warehouse_record__type=WarehouseRecord.TH
- ).aggregate(total_count=Sum('count'))
- if sum_row:
- count = sum_row['total_count'] or 0
- return -count
- @staticmethod
- def _updateMainRedundant(goods_entry_ids,inventory_ids,entry_ids):
- goods_entry_ids = list(set(goods_entry_ids))
- inventory_ids = list(set(inventory_ids))
- entry_ids = list(set(entry_ids))
- for id in goods_entry_ids:
- row = GoodsGodownEntry.objects.filter(id=id).first()
- if row:
- row.update_redundant()
- for id in inventory_ids:
- row = Inventory.objects.filter(id=id).first()
- if row:
- row.update_redundant()
- for id in entry_ids:
- row = GodownEntry.objects.filter(id=id).first()
- if row:
- row.update_redundant()
- # 获取金额
- @staticmethod
- def tryDelivered(product,warehouse,count):
- amount = 0
- amount2 = 0
- max_entry_price = 0
- max_entry_price2 = 0
- stock_records = WarehouseStockRecord.objects.filter(
- product=product,
- warehouse=warehouse,
- surplus_count__gt=0
- ).order_by('entry_time')
- for row in stock_records:
- if row.surplus_count >= count:
- cur_count = count
- else:
- cur_count = row.surplus_count
- amount += cur_count * row.entry_price
- amount2 += cur_count * row.entry_price2
- if row.entry_price > max_entry_price:
- max_entry_price = row.entry_price
- max_entry_price2 = row.entry_price2
- count -= cur_count
- if not count:
- break
- if count:
- warehouse_stock = WarehouseStock.getByWarehouseAndProduct(warehouse,product)
- amount += count * warehouse_stock.avg_cost_price
- amount2 += count * warehouse_stock.avg_cost_price2
- if warehouse_stock.avg_cost_price > max_entry_price:
- max_entry_price = warehouse_stock.avg_cost_price
- max_entry_price2 = warehouse_stock.avg_cost_price2
- return amount, amount2, max_entry_price, max_entry_price2
- # 入库
- @staticmethod
- def entry(type,product,warehouse,supplier,entry_count,entry_price,entry_price2):
- rk_types = (WarehouseRecord.RK_ZJ,WarehouseRecord.RK_CG,WarehouseRecord.RK_PY)
- if entry_count <= 0:
- raise CustomError(u'[%s]入库数量不能小于等于0' % product.name)
- if entry_price < 0 or entry_price2 < 0:
- raise CustomError(u'[%s]入库价不能小于0' % product.name)
- if type not in rk_types:
- raise CustomError(u'[%s]入库类型错误' % product.name)
- warehouse_record = WarehouseRecord.objects.create(
- type=type,
- product=product,
- warehouse=warehouse,
- count=entry_count,
- amount=entry_count * entry_price,
- amount2=entry_count * entry_price2
- )
- warehouse_stock_record = WarehouseStockRecord.objects.create(
- product=product,
- warehouse=warehouse,
- supplier=supplier,
- entry_count=entry_count,
- entry_price=entry_price,
- entry_price2=entry_price2,
- surplus_count=entry_count
- )
- WarehouseRecordDetail.objects.create(
- warehouse_record=warehouse_record,
- warehouse_stock_record=warehouse_stock_record,
- count=entry_count
- )
- warehouse_stock = WarehouseStock.getByWarehouseAndProduct(warehouse,product)
- if type != WarehouseRecord.RK_PY:
- warehouse_stock.last_entry_price = entry_price
- product.last_entry_price = entry_price
- warehouse_stock.last_entry_time = timezone.now()
- product.last_entry_time = timezone.now()
- BizWarehouse._updateStock(warehouse_stock, warehouse_record)
- BizWarehouse._updateProductStock(product)
- return warehouse_stock_record
- # 出库
- @staticmethod
- def delivered(type,product,warehouse,count):
- ck_types = (WarehouseRecord.CK_ZJ,WarehouseRecord.CK_XS,WarehouseRecord.CK_PK)
- if count <= 0:
- raise CustomError(u'[%s]出库数量不能小于等于0' % product.name)
- if type not in ck_types:
- raise CustomError(u'[%s]出库类型错误' % product.name)
- stock_records = WarehouseStockRecord.objects.filter(
- product=product,
- warehouse=warehouse,
- surplus_count__gt=0
- ).order_by('entry_time')
- warehouse_record = WarehouseRecord.objects.create(
- type=type,
- product=product,
- warehouse=warehouse,
- count=-count,
- amount=0,
- amount2=0
- )
- BizWarehouse._deliveredForStockRecords(warehouse_record,stock_records)
- warehouse_stock = WarehouseStock.getByWarehouseAndProduct(warehouse,product)
- warehouse_stock.last_deliverd_time = timezone.now()
- product.last_deliverd_time = timezone.now()
- BizWarehouse._updateStock(warehouse_stock,warehouse_record)
- BizWarehouse._updateProductStock(product)
- BizWarehouse.updateRedundant(warehouse_record)
- return warehouse_record
- # 根据指定库存出库
- @staticmethod
- def deliveredByStockRecord(type,stock_record,count):
- product = stock_record.product
- warehouse = stock_record.warehouse
- if count <= 0:
- raise CustomError(u'[%s]出库数量不能小于等于0' % product.name)
- if count > stock_record.surplus_count:
- raise CustomError(u'[%s]出库数量超出对应入库记录的剩余数量' % product.name)
- warehouse_record = WarehouseRecord.objects.create(
- type=type,
- product=product,
- warehouse=warehouse,
- count=-count,
- amount=0,
- amount2=0
- )
- stock_records = (stock_record,)
- BizWarehouse._deliveredForStockRecords(warehouse_record, stock_records)
- warehouse_stock = WarehouseStock.getByWarehouseAndProduct(warehouse,product)
- warehouse_stock.last_deliverd_time = timezone.now()
- product.last_deliverd_time = timezone.now()
- BizWarehouse._updateStock(warehouse_stock, warehouse_record)
- BizWarehouse._updateProductStock(product)
- BizWarehouse.updateRedundant(warehouse_record)
- return warehouse_record
- # 退料
- @staticmethod
- def deliveredBack(warehouse_record, count):
- if count <= 0:
- raise CustomError(u'[%s]退料数量不能小于等于0' % warehouse_record.product.name)
- data = BizWarehouse._getDeliveredBackDetail(warehouse_record, count)
- res = BizWarehouse._deliveredBackByDetails(WarehouseRecord.TL,warehouse_record,data)
- BizWarehouse.updateRedundant(res)
- return res
- # 退货
- @staticmethod
- def entryBack(stock_record,count):
- product = stock_record.product
- warehouse = stock_record.warehouse
- if count <= 0:
- raise CustomError(u'[%s]退货数量不能小于等于0' % product.name)
- if count > stock_record.surplus_count:
- raise CustomError(u'[%s]退货数量超出对应入库记录的剩余数量' % product.name)
- warehouse_record = WarehouseRecord.objects.create(
- type=WarehouseRecord.TH,
- product=product,
- warehouse=warehouse,
- count=-count,
- amount=0,
- amount2=0
- )
- stock_records = (stock_record,)
- BizWarehouse._deliveredForStockRecords(warehouse_record, stock_records)
- warehouse_stock = WarehouseStock.getByWarehouseAndProduct(warehouse,product)
- BizWarehouse._updateStock(warehouse_stock, warehouse_record)
- BizWarehouse._updateProductStock(product)
- BizWarehouse.updateRedundant(warehouse_record)
- return warehouse_record
- # 批量退货
- @staticmethod
- def entryBatchBack(product,warehouse,count,supplier=None):
- if count <= 0:
- raise CustomError(u'[%s]退货数量不能小于等于0' % product.name)
- stock_records = WarehouseStockRecord.objects.filter(
- product=product,
- warehouse=warehouse,
- surplus_count__gt=0
- )
- if supplier:
- stock_records = stock_records.filter(
- supplier=supplier
- )
- stock_records = stock_records.order_by('entry_time')
- warehouse_record = WarehouseRecord.objects.create(
- type=WarehouseRecord.TH,
- product=product,
- warehouse=warehouse,
- count=-count,
- amount=0,
- amount2=0
- )
- BizWarehouse._deliveredForStockRecords(warehouse_record, stock_records)
- warehouse_stock = WarehouseStock.getByWarehouseAndProduct(warehouse,product)
- BizWarehouse._updateStock(warehouse_stock, warehouse_record)
- BizWarehouse._updateProductStock(product)
- BizWarehouse.updateRedundant(warehouse_record)
- return warehouse_record
- @staticmethod
- def _getDeliveredBackDetail(warehouse_record, count):
- details = WarehouseRecordDetail.objects.filter(
- warehouse_record=warehouse_record
- ).order_by('-warehouse_stock_record__entry_time')
- data = []
- for detail in details:
- back_count = (WarehouseBackMap.objects.filter(delivered_detail=detail).aggregate(count_sum=Sum('back_count')))['count_sum'] or 0
- if back_count >= -detail.count:
- continue
- temp = -(detail.count + back_count)
- if temp >= count:
- cur_count = count
- else:
- cur_count = temp
- data.append({'delivered_detail': detail, 'back_count': cur_count})
- count -= cur_count
- if not count:
- break
- if count:
- raise CustomError(u'[%s]退料数量超出出库剩余数量' % warehouse_record.product.name)
- return data
- @staticmethod
- def _deliveredBackByDetails(type, warehouse_record, details):
- product = warehouse_record.product
- warehouse = warehouse_record.warehouse
- item = WarehouseRecord.objects.create(
- type=type,
- product=warehouse_record.product,
- warehouse=warehouse_record.warehouse,
- count=0,
- amount=0,
- amount2=0
- )
- for detail in details:
- warehouse_stock_record = detail['delivered_detail'].warehouse_stock_record
- back_detail = WarehouseRecordDetail.objects.create(
- warehouse_record=item,
- warehouse_stock_record=warehouse_stock_record,
- count=detail['back_count']
- )
- warehouse_stock_record.surplus_count += detail['back_count']
- warehouse_stock_record.save()
- WarehouseBackMap.objects.create(
- back_detail=back_detail,
- delivered_detail=detail['delivered_detail'],
- back_count=detail['back_count']
- )
- item.count += detail['back_count']
- sum_row = WarehouseRecordDetail.objects.filter(
- warehouse_record=item
- ).aggregate(
- sum_amount=Sum(F('count') * F('warehouse_stock_record__entry_price')),
- sum_amount2=Sum(F('count') * F('warehouse_stock_record__entry_price2'))
- )
- item.amount = sum_row['sum_amount']
- item.amount2 = sum_row['sum_amount2']
- item.save()
- warehouse_stock = WarehouseStock.getByWarehouseAndProduct(warehouse,product)
- BizWarehouse._updateStock(warehouse_stock, item)
- BizWarehouse._updateProductStock(product)
- return item
- @staticmethod
- def _deliveredForStockRecords(warehouse_record,stock_records):
- product = warehouse_record.product
- temp_count = -warehouse_record.count
- for row in stock_records:
- if row.surplus_count >= temp_count:
- cur_count = temp_count
- else:
- cur_count = row.surplus_count
- row.surplus_count -= cur_count
- row.save()
- WarehouseRecordDetail.objects.create(
- warehouse_record=warehouse_record,
- warehouse_stock_record=row,
- count=-cur_count
- )
- temp_count -= cur_count
- if not temp_count:
- break
- if temp_count:
- raise CustomError(u'[%s]库存不足' % product.name)
- sum_row = WarehouseRecordDetail.objects.filter(
- warehouse_record=warehouse_record
- ).aggregate(
- sum_amount=Sum(F('count') * F('warehouse_stock_record__entry_price')),
- sum_amount2=Sum(F('count') * F('warehouse_stock_record__entry_price2'))
- )
- warehouse_record.amount = sum_row['sum_amount']
- warehouse_record.amount2 = sum_row['sum_amount2']
- warehouse_record.save()
- @staticmethod
- def _updateStock(warehouse_stock,warehouse_record):
- warehouse_stock.count += warehouse_record.count
- warehouse_stock.amount += warehouse_record.amount
- warehouse_stock.amount2 += warehouse_record.amount2
- if warehouse_stock.count != 0:
- warehouse_stock.avg_cost_price = warehouse_stock.amount / warehouse_stock.count
- warehouse_stock.avg_cost_price2 = warehouse_stock.amount2 / warehouse_stock.count
- warehouse_record.cur_count = warehouse_stock.count
- warehouse_record.cur_amount = warehouse_stock.amount
- warehouse_record.cur_amount2 = warehouse_stock.amount2
- warehouse_record.save()
- warehouse_stock.save()
- @staticmethod
- def _updateProductStock(product):
- sum_row = WarehouseStock.objects.filter(
- product=product
- ).aggregate(
- count=Sum('count'),
- amount=Sum('amount'),
- amount2=Sum('amount2')
- )
- product.stock_count = sum_row['count']
- product.stock_amount = sum_row['amount']
- product.stock_amount2 = sum_row['amount2']
- if product.stock_count != 0:
- product.avg_cost_price = product.stock_amount / product.stock_count
- product.avg_cost_price2 = product.stock_amount2 / product.stock_count
- product.save()
- class GetWarehouseSrockRecord():
- @staticmethod
- def getRecord(product, warehouse, supplier=None):
- record_data = []
- record_rows = WarehouseStockRecord.objects.filter(warehouse_id=warehouse, product_id=product,
- surplus_count__gt=0)
- if supplier:
- record_rows = record_rows.filter(supplier_id=supplier)
- for record_row in record_rows:
- product_base = record_row.product
- if product_base.type == ProductBase.GOODS:
- g_row = GoodsGodownEntryDetail.objects.filter(stock_record_id=record_row.id).first()
- else:
- g_row = GodownEntryDetail.objects.filter(stock_record_id=record_row.id).first()
- if not g_row:
- g_row = InventoryDetail.objects.filter(warehouse_stock_record_id=record_row.id).first()
- record_item = {
- 'stock_id': record_row.id,
- 'no': g_row.main.no,
- 'entry_price': Formater.formatPriceShow(record_row.entry_price),
- 'surplus_count': Formater.formatCountShow(record_row.surplus_count),
- 'detail_id': g_row.id,
- 'notes': g_row.main.notes or ''
- }
- record_data.append(record_item)
- return record_data
|