Example #1
0
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
Example #2
0
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)
Example #3
0
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
Example #4
0
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()
Example #5
0
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')
Example #6
0
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
Example #7
0
File: models.py Project: pbpoon/dda
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
Example #8
0
File: models.py Project: pbpoon/dda
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
Example #9
0
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, ''