class PurchaseOrder(OrderAbstract): partner = models.ForeignKey('partner.Supplier', on_delete=models.CASCADE, related_name='purchase_order', verbose_name='供应商') order = OrderField( order_str='PO', max_length=10, default='New', db_index=True, unique=True, verbose_name='订单号码', ) currency = models.CharField('货币', choices=CURRENCY_CHOICE, max_length=10) uom = models.CharField('计量单位', null=False, choices=UOM_CHOICES, max_length=10) batch = models.CharField('批次', max_length=10, blank=True, null=True, help_text='如果不填,则采取"-"号前或编号前2位作为批次号') category = models.ForeignKey('product.Category', on_delete=models.CASCADE, verbose_name='品种分类') quarry = models.ForeignKey('product.Quarry', on_delete=models.CASCADE, verbose_name='矿口') invoices = GenericRelation('invoice.PurchaseInvoice') class Meta: verbose_name = '采购订单' ordering = ['-order'] def __str__(self): return self.order def get_absolute_url(self): return reverse('purchase_order_detail', args=[self.id]) def get_quantity(self): return sum(item.get_quantity() for item in self.items.all()) def get_total(self): """ template使用方式 {% for key, item in object.get_total.items %} {{ key }}:{% if item.part %}{{ item.part }}夹 / {% endif %}{{ item.piece }}件 / {{ item.quantity }}{{ item.uom }}<br> {% endfor %} """ if not self.items.all(): return total = {} for item in self.items.all(): if not item.product: continue d = collections.defaultdict(lambda: 0) a = total.setdefault(item.product.get_type_display(), d) a['piece'] += item.piece a['quantity'] += item.quantity # d['part'] += item.package_list.get_part() if item.package_list else 0 a['uom'] = item.uom # total.setdefault(item.product.get_type_display(), {}).update(d) return total @property def amount(self): return self.get_amount() def get_amount(self): return sum(item.get_amount() for item in self.items.all()) def get_create_item_url(self): return reverse('purchase_order_item_create', args=[self.id]) def get_update_url(self): return reverse('purchase_order_update', args=[self.id]) def confirm(self, **kwargs): for item in self.items.all(): item.confirm() self.state = 'confirm' self.save() # 日后生产invoice self.create_comment(**kwargs) msg = '设置订单%s设置成 %s 状态' % (self.order, self.get_state_display()) return True, msg def draft(self, **kwargs): for item in self.items.all(): item.draft() self.state = 'draft' self.save() self.create_comment(**kwargs) msg = '设置订单%s设置成 %s 状态' % (self.order, self.get_state_display()) return True, msg def done(self, **kwargs): self.create_comment(**kwargs) return True, '' def _get_invoice_usage(self): return '采购货款' # @property # def invoices(self): # from invoice.models import PurchaseInvoice # # invoices = set(self.invoices.all()) # invoices = PurchaseInvoice.objects.none() # for item in self.items.all(): # for item in item.invoice_items.all(): # invoices |= item.order # # invoices |= {invoice.order for item in self.items.all() for invoice in item.invoice_items.all().distinct()} # return invoices @property def can_make_invoice_amount(self): return sum(item.get_can_make_invoice_amount() for item in self.items.all()) def make_invoice(self): items_dict = {} for item in self.items.all(): items_dict.update(item.prepare_invoice_item()) state = self.state if self.state != 'done' else 'confirm' return CreateInvoice(self, self.partner, items_dict, type=-1, state=state).invoice
class ProductionOrder(MrpOrderAbstract): order = OrderField(order_str='MO', blank=True, verbose_name='单号', default='New', max_length=20) production_type = models.ForeignKey(ProductionType, on_delete=models.CASCADE, verbose_name='业务类型', limit_choices_to={'activate': True}) partner = models.ForeignKey('partner.Partner', on_delete=models.CASCADE, verbose_name='生产单位', limit_choices_to={'type': 'production'}) class Meta: verbose_name = '生产订单' ordering = ('-date', '-created') def _get_invoice_usage(self): return '%s费用' % self.production_type.name def get_absolute_url(self): return reverse('production_detail', args=[self.id]) def get_update_url(self): return reverse('production_update', args=[self.id]) def get_create_item_url(self): return reverse('production_raw_item_create', args=[self.id]) def get_location(self): return self.warehouse.get_main_location() def get_location_dest(self): return self.warehouse.get_production_location() def get_total(self): """ template使用方式 {% for key, item in object.get_total.items %} {{ key }}:{% if item.part %}{{ item.part }}夹 / {% endif %}{{ item.piece }}件 / {{ item.quantity }}{{ item.uom }}<br> {% endfor %} """ total = {} for item in self.get_all_items(): if not item.product: continue d = collections.defaultdict(lambda: 0) a = total.setdefault(item.product.get_type_display(), d) a['piece'] += item.piece if item.piece else 0 a['quantity'] += item.quantity if item.quantity else 0 a['part'] += item.package_list.get_part( ) if item.package_list else 0 a['uom'] = item.uom return total def get_stock(self): items = list(self.items.all()) items.extend(list(self.produce_items.all())) return StockOperate(order=self, items=items) def get_invoices(self): invoices = set(self.invoices.all()) invoices |= { invoice.order for item in self.items.all() for invoice in item.invoice_items.all().distinct() } return invoices def done(self, **kwargs): is_done, msg = self.get_stock().handle_stock() if is_done: self.state = 'done' self.save() self.create_comment(**kwargs) self.make_invoice() self.make_expenses_invoice() return is_done, msg def cancel(self, **kwargs): self.state = 'cancel' self.save() self.create_comment(**kwargs) for invoice in self.get_invoices(): invoice.state = 'cancel' invoice.save() comment = '更新 %s <a href="%s">%s</a>状态:%s, 修改本账单' % ( self._meta.verbose_name, self.get_absolute_url(), self, self.state) invoice.create_comment(**{'comment': comment}) return True, '' def get_all_items(self): items = list(self.items.all()) items.extend(list(self.produce_items.all())) return items def get_make_invoice_items(self): if self.production_type.expense_by == 'raw': return self.items.all() elif self.production_type.expense_by == 'produce': return self.produce_items.all() else: return self.get_all_items() def make_invoice(self): items = self.get_make_invoice_items() items_dict = {} for item in items: items_dict.update(item.prepare_invoice_item()) state = self.state if self.state != 'done' else 'confirm' return CreateInvoice(self, self.partner, items_dict, type=-1, state=state).invoice def get_expenses_amount(self): return sum(item.get_expenses_amount() for item in self.get_all_items()) def make_expenses_invoice(self): from partner.models import Partner from invoice.models import Account, CreateInvoice if self.get_expenses_amount() > 0: items_dict = {} for item in self.get_all_items(): items_dict.update(item.prepare_invoice_item()) if items_dict: partner = Partner.get_expenses_partner( ) if not self.partner else self.partner return CreateInvoice(self, partner, items_dict, usage='杂费', state='confirm', type=-1)
class SalesOrder(OrderAbstract): order = OrderField(order_str='SO', max_length=26, default='New', db_index=True, unique=True, verbose_name='订单号码', ) partner = models.ForeignKey('partner.Customer', on_delete=models.CASCADE, verbose_name='客户名称', related_name='sales_order') province = models.ForeignKey('partner.Province', verbose_name='省份', null=True, blank=True, on_delete=models.SET_NULL) city = models.ForeignKey('partner.City', verbose_name='城市', null=True, blank=True, on_delete=models.SET_NULL) invoices = GenericRelation('invoice.SalesInvoice') class Meta: verbose_name = '销售订单' permissions = (('can_audit', '审核'),) ordering = ['-date', '-id', '-created'] def __str__(self): return self.order @property def progress(self): status = '' # if self.state == 'confirm': out_order_percentage = self.get_out_order_percentage() if self.due_amount > 0: if self.confirm_amount: status += '有付款,未付清,' else: status += '未付款,' elif self.due_amount <= 0 and self.confirm_amount: status += '已付款,' if out_order_percentage == 0: status += '未提货' elif out_order_percentage == 1 or out_order_percentage > 0.99: status += '已提货' elif out_order_percentage > 0 or out_order_percentage <= 0.99: status += '有提货,未提完' return status def get_address(self): if self.province: address = self.province.name address += '/{}'.format(self.city if self.city else self.province.get_city()[0].name) return address return self.partner.get_address() def get_absolute_url(self): return reverse('sales_order_detail', args=[self.id]) def get_create_item_url(self): return reverse('sales_order_item_create', args=[self.id]) def get_update_url(self): return reverse('sales_order_update', args=[self.id]) def get_delete_url(self): return reverse('sales_order_delete', args=[self.id]) def get_list_url(self): return reverse('sales_order_list', args=[self.id]) @property def amount(self): return sum(item.amount for item in self.items.all()) @property def due_amount(self): return self.amount - self.confirm_amount @property def confirm_amount(self): return sum( invoice.confirm_amount for invoice in self.invoices.filter(state__in=('confirm', 'done'), type='1')) # return sum(invoice.amount for item in self.items.all() for invoice in # item.invoice_items.filter(order__state='done').distinct()) # @property # def assign_amounts(self): # # return sum(invoice.confirm_amount for invoice in self.invoices.all()) # return sum(invoice.amount for item in self.items.all() for invoice in # item.invoice_items.filter(order__state='confirm').distinct()) def get_piece(self): return sum(item.piece for item in self.items.all() if item.piece) @property def quantity(self): return sum(item.quantity for item in self.items.all() if item.quantity) def get_total(self): """ template使用方式 {% for key, item in object.get_total.items %} {{ key }}:{% if item.part %}{{ item.part }}夹 / {% endif %}{{ item.piece }}件 / {{ item.quantity }}{{ item.uom }}<br> {% endfor %} """ total = {} for item in self.items.all(): d = collections.defaultdict(lambda: 0) a = total.setdefault(item.product.get_type_display(), d) a['piece'] += item.piece if item.piece else 0 a['quantity'] += item.quantity if item.quantity else 0 a['part'] += item.package_list.get_part() if item.package_list else 0 a['uom'] = item.uom return total # 提货进度百分比 def get_out_order_percentage(self): out_order_total_quantity = sum( order.get_quantity() for order in self.in_out_order.filter(state='done')) # if self.get_piece() - sum( # order.get_ for order in self.in_out_order.filter(state='done') for item in order.items.all()) == 0: # return 1 if self.quantity != 0: number = (out_order_total_quantity / self.quantity) else: number = 0 return number def get_can_in_out_order_qty(self): quantity, piece, part = 0, 0, 0 for item in self.items.all(): qty = item.get_can_in_out_order_qty() if qty['piece'] > 0: quantity += qty['quantity'] piece += qty['piece'] part += qty['part'] return {'quantity': quantity, 'piece': piece, 'part': part} def confirm(self, **kwargs): is_done, msg = StockOperate(self, self.items.all()).reserve_stock() if is_done: self.state = 'confirm' self.save() self.create_comment(**kwargs) self.make_invoice() comment = '更新<a href="%s">%s</a>状态:%s, 修改本账单' % (self.get_absolute_url(), self, self.state) for invoice in self.invoices.all(): if invoice.state != 'draft': continue invoice.state = 'confirm' invoice.save() invoice.create_comment(**{'comment': comment}) return is_done, msg return False, msg def done(self, **kwargs): # if self.get_can_in_out_order_qty()['piece'] == 0 and (int(self.amount) - int(self.due_amount)) <= 0: if self.get_can_in_out_order_qty()['piece'] == 0 and self.due_amount <= 0: self.state = 'done' self.save() if kwargs.get('comment'): kwargs['comment'] += '本订单已全部提货,完成收款' self.create_comment(**kwargs) if self.state == 'done': return True, '' return False, '' def draft(self, **kwargs): is_done, msg = True, '' if self.state == 'confirm': if self.in_out_order.filter(Q(state='confirm') | Q(state='done')).exists(): return False, '已有提货单为出库状态' is_done, msg = StockOperate(self, self.items.all()).reserve_stock(unlock=True) if self.state == 'done': is_done, msg = False, '不能把已完成的订单设置为:取消' if is_done: self.state = 'draft' self.save() self.create_comment(**kwargs) comment = '更新<a href="%s">%s</a>状态:%s, 修改本账单' % (self.get_absolute_url(), self, self.state) for invoice in self.invoices.all(): invoice.state = 'draft' invoice.save() invoice.create_comment(**{'comment': comment}) return is_done, msg def cancel(self, **kwargs): is_done, msg = True, '' if self.state == 'confirm': if self.in_out_order.filter(Q(state='confirm') | Q(state='done')).exists(): return False, '已有提货单为出库状态' is_done, msg = StockOperate(self, self.items.all()).reserve_stock(unlock=True) if self.state == 'done': is_done, msg = False, '不能把已完成的订单设置为:取消' if is_done: self.state = 'cancel' self.save() self.create_comment(**kwargs) comment = '更新<a href="%s">%s</a>状态:%s, 修改本账单' % (self.get_absolute_url(), self, self.state) for invoice in self.invoices.all(): invoice.state = 'cancel' invoice.save() invoice.create_comment(**{'comment': comment}) return is_done, msg def _get_invoice_usage(self): return '销售货款' @property def assigns(self): from invoice.models import Assign assigns = Assign.objects.none() for invoice in self.invoices.filter(state__in=('confirm', 'done')): assigns |= invoice.assign_payments.all() return assigns @property def can_make_invoice_amount(self): return sum(item.get_can_make_invoice_amount() for item in self.items.all()) def make_invoice(self): items_dict = {} for item in self.items.all(): # invoice_line = item.prepare_invoice_item() # if invoice_line in items_dict: # items_dict[invoice_line]['quantity'] += invoice_line['quantity'] # else: # items_dict.update(item.prepare_invoice_item()) items_dict.update(item.prepare_invoice_item()) state = self.state if self.state != 'done' else 'confirm' return CreateInvoice(self, self.partner, items_dict, type=1, state=state).invoice
class InOutOrder(MrpOrderAbstract): type = models.CharField('出入库类型', choices=OPERATION_TYPE, max_length=10) order = OrderField(order_str='IO', blank=True, verbose_name='单号', default='New', max_length=20) counter = models.IntegerField('货柜数', blank=True, null=True) purchase_order = models.ForeignKey('purchase.PurchaseOrder', on_delete=models.CASCADE, verbose_name='采购单', related_name='in_out_order', blank=True, null=True) sales_order = models.ForeignKey('sales.SalesOrder', on_delete=models.CASCADE, verbose_name='销售单', related_name='in_out_order', blank=True, null=True) warehouse = models.ForeignKey('stock.Warehouse', on_delete=models.CASCADE, verbose_name='仓库') cart_number = models.CharField('车牌/柜号', max_length=20, blank=True, null=True) pickup_staff = models.CharField('提货人', max_length=12, blank=True, null=True) class Meta: verbose_name = '出入库操作' ordering = ('-date', '-created') def _get_invoice_usage(self): return '杂费' @property def from_order(self): return self.sales_order or self.purchase_order def __str__(self): return '[{}]{}'.format(self.get_type_display(), self.order) def get_absolute_url(self): return reverse('in_out_order_detail', args=[self.id]) def get_create_item_url(self): return reverse('in_out_order_item_create', args=[self.id]) def get_delete_url(self): return reverse('in_out_order_delete', args=[self.id]) def get_location(self): if self.type == 'in': loc = self.purchase_order.partner.get_location() else: loc = self.warehouse.get_main_location() return loc def get_location_dest(self): if self.type == 'out': loc = self.sales_order.partner.get_location() else: loc = self.warehouse.get_main_location() return loc def get_products_amount(self): return sum(item.quantity * item.get_from_order_item().price for item in self.items.all()) def get_stock(self): return StockOperate(self, self.items.all()) def get_expenses_amount(self): return sum(item.get_expenses_amount() for item in self.items.all()) def done(self, **kwargs): stock = self.get_stock() pieces = 0 for item in self.items.all(): pieces += item.piece if self.sales_order: # 如果是对应的是销售订单 unlock, unlock_msg = stock.reserve_stock(unlock=True) # 如果解库成功就操作库存移动 # 否则就把不能解库的状态及msg返回 print('unlock=%s,msg=%s' % (unlock, unlock_msg)) if unlock: is_done, msg = stock.handle_stock() # 如果库存移动成功就更改状态并create comment # 否则就把不能库存移动的状态及msg返回 print('handle_stock=%s,msg=%s' % (is_done, msg)) if is_done: self.make_invoice() self.state = 'done' self.save() self.create_comment(**kwargs) comment = '完成 %s :<a href="%s">%s</a>' % (self._meta.verbose_name, self.get_absolute_url(), self,) self.from_order.done(**{'comment': comment}) else: stock.reserve_stock() return is_done, msg return unlock, unlock_msg else: # 如果是对应的是采购订单 is_done, msg = stock.handle_stock() if is_done: # 如果库存移动成功就更改状态及create comment self.make_invoice() self.state = 'done' self.save() self.create_comment(**kwargs) comment = '完成 %s :<a href="%s">%s</a>' % (self._meta.verbose_name, self.get_absolute_url(), self) self.from_order.done(**{'comment': comment}) return is_done, msg def cancel(self, **kwargs): stock = self.get_stock() if self.sales_order.state == 'confirm': is_done, msg = stock.reserve_stock() if is_done: self.state = 'cancel' self.save() self.create_comment(**kwargs) comment = '更改 %s <a href="%s">%s</a>状态:%s, 取消本账单' % ( self._meta.verbose_name, self.get_absolute_url(), self, self.state) for invoice in self.invoices.all(): invoice.cancel(**{'comment': comment}) return is_done, msg @property def has_from_order_invoice(self): if self.invoices.all(): from_order_items_ids = {item.get_from_order_item() for item in self.items.all()} for invoice in self.invoices.all(): for item in invoice.items.all(): if item.from_order_item in from_order_items_ids: return True return False def make_from_order_invoice(self): type = -1 if self.type == 'in' else 1 items_dict = {} state = self.state if self.state != 'done' else 'confirm' for item in self.items.all(): items_dict.update(item.prepare_from_order_invoice_item()) return CreateInvoice(self.from_order, self.from_order.partner, items_dict, usage='货款', type=type, state=state).invoice def make_invoice(self): from partner.models import Partner lst = unpack_lst(item.prepare_expenses_invoice_item() for item in self.items.all()) if lst: items_dict = {} for dt in lst: items_dict[dt['item']] = dt payment = {'partner': Partner.get_expenses_partner(), 'account': Account.get_expense_account()} return CreateInvoice(self, Partner.get_expenses_partner(), items_dict, usage='杂费', state='confirm', payment=payment) def make_purchase_order_items(self): # 如果是新建状态 # 该采购单已收货的items取出 already_check_in_items = self.purchase_order.items.filter( order__in_out_order__state__in=('confirm', 'done')) purchase_order_items = self.purchase_order.items.all() if already_check_in_items: purchase_order_items.exclude(product_id__in=[item.product.id for item in already_check_in_items]) for item in purchase_order_items: InOutOrderItem.objects.create(product=item.product, piece=item.piece, quantity=item.quantity, uom=item.uom, order=self, purchase_order_item=item) def make_sales_order_items(self): # 选出产品类型为荒料的已出货项的 from_order_items = self.sales_order.items.all() for item in from_order_items: if item.get_can_in_out_order_qty()['piece'] > 0: stock = item.product.stock.filter( location_id__in=self.warehouse.get_main_location().get_child_list(), product=item.product).distinct() if not stock: continue if item.package_list: package = item.package_list.make_package_from_list(item.product_id, from_package_list=item.package_list) else: package = None defaults = {'piece': stock[0].piece, 'quantity': stock[0].quantity, 'package_list': package, 'product': item.product, 'order': self, 'uom': item.uom, 'sales_order_item': item} InOutOrderItem.objects.create(**defaults) def make_items(self): # 如果是update状态,有object就返回items if self.purchase_order: return self.make_purchase_order_items() return self.make_sales_order_items() def save(self, *args, **kwargs): new = False if not self.pk: new = True super().save(*args, **kwargs) if new: self.make_items()
class MoveLocationOrder(MrpOrderAbstract): partner = models.ForeignKey('partner.Partner', on_delete=models.SET_NULL, null=True, blank=True, limit_choices_to={'type': 'service'}, verbose_name='运输单位') order = OrderField(order_str='MO', blank=True, verbose_name='单号', default='New', max_length=20) warehouse = models.ForeignKey('stock.Warehouse', on_delete=models.CASCADE, verbose_name='移出仓库', related_name='move_out_warehouse') warehouse_dest = models.ForeignKey('stock.Warehouse', on_delete=models.CASCADE, verbose_name='接收仓库', related_name='move_in_warehouse') class Meta: verbose_name = '移库单' ordering = ('-date', '-created') @property def type(self): if self.partner: return '仓库调拨单' return self._meta.verbose_name def _get_invoice_usage(self): return '运输费' def get_location(self): return self.warehouse.get_main_location() def get_location_dest(self): return self.warehouse_dest.get_main_location() def get_create_item_url(self): return reverse('move_location_order_item_create', args=[self.id]) def get_absolute_url(self): return reverse('move_location_order_detail', args=[self.id]) def get_update_url(self): return reverse('move_location_order_update', args=[self.id]) def get_delete_url(self): return reverse('move_location_order_delete', args=[self.id]) def get_stock(self): from public.stock_operate import StockOperate return StockOperate(order=self, items=self.items.all()) def get_expenses_amount(self): return sum(item.get_expenses_amount() for item in self.items.all()) def done(self, **kwargs): stock = self.get_stock() if self.state == 'confirm': is_done, msg = stock.reserve_stock(unlock=True) if not is_done: return is_done, msg is_done, msg = stock.handle_stock() if is_done: self.state = 'done' self.save() self.create_comment(**kwargs) self.make_expenses_invoice() return is_done, msg def confirm(self, **kwargs): stock = self.get_stock() is_done, msg = stock.reserve_stock() if is_done: self.state = 'confirm' self.save() self.create_comment(**kwargs) return is_done, msg def draft(self, **kwargs): stock = self.get_stock() if self.state == 'confirm': is_done, msg = stock.reserve_stock(unlock=True) if is_done: self.state = 'draft' self.save() self.create_comment(**kwargs) return is_done, msg return False, '' def cancel(self, **kwargs): is_done, msg = True, '' if self.state == 'confirm': stock = self.get_stock() is_done, msg = stock.reserve_stock(unlock=True) if not is_done: return is_done, msg self.state = 'cancel' self.save() self.create_comment(**kwargs) else: # 来自turn back order self.state = 'cancel' self.save() self.create_comment(**kwargs) comment = '更改 %s <a href="%s">%s</a>状态:%s, 取消本账单' % ( self._meta.verbose_name, self.get_absolute_url(), self, self.state) for invoice in self.invoices.all(): invoice.cancel(**{'comment': comment}) for invoice in self.invoices.all(): comment = '更新 %s <a href="%s">%s</a>状态:%s, 修改本账单' % ( self._meta.verbose_name, self.get_absolute_url(), self, self.state) # invoice.create_comment(**{'comment': comment}) invoice.cancel(**{'comment': comment}) return is_done, msg def make_expenses_invoice(self): from partner.models import Partner from invoice.models import CreateInvoice if self.get_expenses_amount() > 0: items_dict = {} for item in self.items.all(): items_dict.update(item.prepare_expenses_invoice_item()) if items_dict: partner = Partner.get_expenses_partner( ) if not self.partner else self.partner return CreateInvoice(self, partner, items_dict, usage='运输费', state='confirm')
class TurnBackOrder(HasChangedMixin, models.Model): content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() from_order = GenericForeignKey() # 对应的order state = models.CharField('状态', choices=STATE_CHOICES, max_length=20, default='draft') reason = models.CharField('原因', max_length=80) order = OrderField(order_str='TB', blank=True, verbose_name='单号', default='New', max_length=20) warehouse = models.ForeignKey('stock.Warehouse', on_delete=models.CASCADE, verbose_name='接收仓库', blank=True, null=True, help_text='如果没有指定,将会按原单出库仓库接受') handler = models.ForeignKey('auth.User', on_delete=models.CASCADE, verbose_name='经办人', related_name='%(class)s_handler') entry = models.ForeignKey('auth.User', on_delete=models.CASCADE, verbose_name='登记人', related_name='%(class)s_entry') date = models.DateField('日期', default=datetime.now) created = models.DateField('创建日期', auto_now_add=True) updated = models.DateTimeField('更新时间', auto_now=True) comments = GenericRelation('comment.Comment') invoices = GenericRelation('invoice.Invoice') files = GenericRelation('files.Files') class Meta: verbose_name = '库存回退' ordering = ('-date', '-created') def get_obj(self): return self.content_type.model_class().objects.get(pk=self.object_id) def get_absolute_url(self): return reverse('turn_back_order_detail', args=[self.id]) def get_delete_url(self): return reverse('turn_back_order_delete', args=[self.id]) def __str__(self): return '{}/库存回退({})'.format(self.get_obj(), self.order[-8:]) def get_stock(self): return StockOperate(order=self, items=self.items.all()) def done(self): is_done, msg = self.get_stock().handle_stock() if is_done: comment = '通过 %s <a herf="%s">%s</a>状态:%s, 取消本订单,原因是:%s,库存已逆向操作成功' % ( self._meta.verbose_name, self.get_absolute_url(), self, self.state, self.reason) form_order = self.get_obj() is_cancel, cancel_msg = form_order.cancel(**{'comment': comment}) self.state = 'done' self.save() self.create_comment() if not is_cancel: return is_cancel, cancel_msg return is_done, msg def get_total(self): """ template使用方式 {% for key, item in object.get_total.items %} {{ key }}:{% if item.part %}{{ item.part }}夹 / {% endif %}{{ item.piece }}件 / {{ item.quantity }}{{ item.uom }}<br> {% endfor %} """ d = collections.defaultdict(lambda: 0) total = {} for item in self.items.all(): a = total.setdefault(item.product.get_type_display(), d) a['piece'] += item.piece a['quantity'] += item.quantity a['part'] += item.package_list.get_part( ) if item.package_list else 0 a['uom'] = item.uom return total def get_files(self): files = self.files.all() if files.count() > 10: files = files[:10] return files
class OrderAbstract(HasChangedMixin, models.Model): state = models.CharField('状态', choices=STATE_CHOICES, max_length=20, default='draft') order = OrderField( order_str=None, max_length=26, default='New', db_index=True, unique=True, verbose_name='订单号码', ) partner = models.ForeignKey('partner.Partner', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='业务伙伴') date = models.DateField('日期') created = models.DateField('创建日期', auto_now_add=True) updated = models.DateTimeField('更新时间', auto_now=True) handler = models.ForeignKey('auth.User', on_delete=models.CASCADE, verbose_name='经办人', related_name='%(class)s_handler') entry = models.ForeignKey('auth.User', on_delete=models.CASCADE, verbose_name='登记人', related_name='%(class)s_entry') comments = GenericRelation('comment.Comment') invoices = GenericRelation('invoice.Invoice') files = GenericRelation('files.Files') tasks = GenericRelation('tasks.Tasks') # operation_logs = GenericRelation('comment.OperationLogs') class Meta: abstract = True ordering = ['-date', '-created'] @property def invoice_usage(self): return self._get_invoice_usage() def _get_invoice_usage(self): raise ValueError('define invoice_usage') def get_quantity(self): return sum(item.quantity for item in self.items.all() if item.quantity) def get_amount(self): return sum(item.get_amount() for item in self.items.all()) def get_total(self): """ template使用方式 {% for key, item in object.get_total.items %} {{ key }}:{% if item.part %}{{ item.part }}夹 / {% endif %}{{ item.piece }}件 / {{ item.quantity }}{{ item.uom }}<br> {% endfor %} """ # if not self.items.all(): # return total = {} for item in self.items.all(): if not item.product: continue d = collections.defaultdict(lambda: 0) a = total.setdefault(item.product.get_type_display(), d) a['piece'] += item.piece a['quantity'] += item.quantity a['part'] += item.package_list.get_part( ) if item.package_list else 0 a['uom'] = item.uom return total def get_files(self): files = self.files.all() if files.count() > 10: files = files[:10] return files
class Invoice(HasChangedMixin, models.Model): state = models.CharField('状态', max_length=10, choices=STATE_CHOICES, default='draft') order = OrderField(order_str='IV', max_length=26, default='New', db_index=True, verbose_name='订单号码') created = models.DateTimeField('创建时间', auto_now_add=True) updated = models.DateTimeField('更新时间', auto_now=True) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() from_order = GenericForeignKey('content_type', 'object_id') date = models.DateField('日期') due_date = models.DateField('到期日') partner = models.ForeignKey('partner.Partner', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='对方', related_name='%(class)s_partner') # payments = models.ManyToManyField('Payment', through='Assign', related_name='assign_invoices') entry = models.ForeignKey('auth.User', on_delete=models.CASCADE, related_name='%(class)s_entry', verbose_name='登记') usage = models.CharField('款项用途', max_length=50) type = models.CharField('付款/收款', choices=TYPE_CHOICES, null=False, max_length=2, default='-1') comments = GenericRelation('comment.Comment') files = GenericRelation('files.Files') tasks = GenericRelation('tasks.Tasks') monitor_fields = ['state', 'partner', 'usage', 'type', 'date', 'due_date'] class Meta: verbose_name = '账单' ordering = ('-created', ) permissions = (('can_draft', '设为草稿'), ('can_cancel', '设为取消')) def get_obj(self): return self.content_type.model_class().objects.get(pk=self.object_id) @property def quantity(self): return Decimal('{0:.2f}'.format( sum(item.quantity for item in self.items.all()))) @property def amount(self): return Decimal('{0:.2f}'.format( sum(item.amount for item in self.items.all()))) @property def due_amount(self): # 未付余额 return self.amount - self.paid_amount @property def confirm_due_amount(self): # 未付余额 return self.amount - self.confirm_amount @property def confirm_amount(self): return sum( assign.amount for assign in self.assign_payments.filter(payment__confirm=True)) @property def paid_amount(self): return sum(assign.amount for assign in self.assign_payments.all()) def get_absolute_url(self): type = self.content_type.model # print(type) if type == 'purchaseorder': return reverse('purchase_invoice_detail', args=[self.id]) elif type == 'salesorder': return reverse('sales_invoice_detail', args=[self.id]) elif type in [ 'inoutorder', 'inventoryorder', 'movelocationorder', 'productionorder', 'turnbackorder' ]: return reverse('expenses_invoice_detail', args=[self.id]) return reverse('invoice_detail', args=[self.id]) def get_update_url(self): return reverse('invoice_update', args=[self.id]) def get_create_item_url(self): return reverse('invoice_item_create', args=[self.id]) @property def all_payment_confirm(self): for assign in self.assign_payments.all(): if not assign.payment.confirm: return False return True def __str__(self): display = '已' if self.state == 'done' else '应' return '{}{}{}/金额:{}'.format(display, self.get_type_display(), self.order, self.amount) def confirm(self, **kwargs): self.state = 'confirm' self.save() self.create_comment(**kwargs) return True, '' def done(self, **kwargs): if self.due_amount == 0 and self.all_payment_confirm: self.state = 'done' self.save() self.create_comment(**kwargs) if self.content_type.model in ('salesorder', 'purchaseorder'): comment = '完成账单:<a href="%s">%s</a>, 金额:%s' % ( self.get_absolute_url(), self, self.amount) self.from_order.done(**{'comment': comment}) return True, '' return False, '该账单下还有金额 {} 未完成付款。'.format(self.due_amount) def cancel(self, **kwargs): msg = '' if self.assign_payments.all(): amt = sum(ass.amount for ass in self.assign_payments.all()) msg = '该账单下被分配的付款金额 {} ,将退回付款方名下,可分配到其他账单'.format(amt) self.assign_payments.all().delete() self.state = 'cancel' self.save() self.create_comment(**kwargs) return True, msg def draft(self, **kwargs): is_done, msg = self.cancel() self.state = 'draft' self.save() self.create_comment(**kwargs) return is_done, msg def quick_assign_due_payment(self, partner, account, entry): payment = Payment.objects.create(date=datetime.date.today(), partner=partner, account=account, type=self.type, amount=self.due_amount, entry=self.entry) Assign.objects.create(invoice=self, payment=payment, amount=payment.amount, entry=entry) def get_files(self): files = self.files.all() if files.count() > 10: files = files[:10] return files
class InventoryOrder(HasChangedMixin, models.Model): name = models.CharField('盘点简述', max_length=100) state = models.CharField('状态', choices=STATE_CHOICES, max_length=20, default='draft') order = OrderField(order_str='INV', blank=True, verbose_name='单号', default='New', max_length=20) warehouse = models.ForeignKey('stock.Warehouse', on_delete=models.CASCADE, verbose_name='仓库', blank=True, null=True, help_text='盘点的仓库') product_type = models.CharField('产品类型', max_length=10, choices=TYPE_CHOICES, blank=True, null=True) handler = models.ManyToManyField('auth.User', verbose_name='经办人', related_name='%(class)s_handler') entry = models.ForeignKey('auth.User', on_delete=models.CASCADE, verbose_name='登记人', related_name='%(class)s_entry') date = models.DateField('日期', default=datetime.now) created = models.DateField('创建日期', auto_now_add=True) updated = models.DateTimeField('更新时间', auto_now=True) comments = GenericRelation('comment.Comment') files = GenericRelation('files.Files') tasks = GenericRelation('tasks.Tasks') class Meta: verbose_name = '盘点库存' ordering = ('-created', ) def get_absolute_url(self): return reverse('inventory_order_detail', args=[self.id]) def get_create_item_url(self): return reverse('inventory_order_new_item_create', args=[self.id]) def get_delete_url(self): return reverse('inventory_order_delete', args=[self.id]) def get_all_items(self): items = list(self.items.all()) items.extend(list(self.new_items.all())) return items def get_files(self): files = self.files.all() if files.count() > 10: files = files[:10] return files # def get_total(self): # """ # template使用方式 # {% for key, item in object.get_total.items %} # {{ key }}:{% if item.part %}{{ item.part }}夹 / {% endif %}{{ item.piece }}件 / {{ item.quantity }}{{ item.uom }}<br> # {% endfor %} # """ # total = {} # for item in self.get_all_items(): # d = collections.defaultdict(lambda: 0) # d['piece'] += item.piece # d['quantity'] += item.quantity # d['part'] += item.package_list.get_part() if item.package_list else 0 # d['uom'] = item.uom # total[item.product.get_type_display()] = d # return total def __str__(self): return self.name def get_stock(self): # 把相等或未盘点的剔出 # items = list(self.items.exclude(Q(report='is_equal') | Q(report=None))) items = [item for item in self.items.all() if item.state != 0] new_items = self.new_items.all() # change_loc_items = self.items.filter(report='is_equal') # if change_loc_items: # items.extend(list(change_loc_items)) if new_items: items.extend(list(new_items)) return StockOperate(self, items) def done(self, **kwargs): is_done, msg = self.get_stock().handle_stock() if is_done: self.state = 'done' self.save() self.create_comment(**kwargs) return is_done, msg def confirm(self): if any((item for item in self.items.all() if not item.is_check)): return False, '有明细行没有进行盘点' self.state = 'confirm' self.save() return True, '' def draft(self): if self.state == 'confirm': self.state = 'draft' self.save() return True, '' return False, ''