mirror of
https://github.com/himool/HimoolERP.git
synced 2024-12-26 00:42:03 +08:00
feat: 销售单据
This commit is contained in:
parent
ec1ef6d3c4
commit
309a8c0f67
18 changed files with 419 additions and 32 deletions
|
@ -29,7 +29,7 @@ class PaymentOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'FK' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'FK' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
@ -76,7 +76,7 @@ class CollectionOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'CK' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'CK' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
@ -129,7 +129,7 @@ class ChargeOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'SZ' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'SZ' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
from extensions.routers import *
|
||||
from apps.purchase.views import *
|
||||
|
||||
|
||||
router = BaseRouter()
|
||||
router.register('purchase_orders', PurchaseOrderViewSet, 'purchase_order')
|
||||
urlpatterns = router.urls
|
||||
|
|
|
@ -13,8 +13,8 @@ class PurchaseOrder(Model):
|
|||
total_quantity = FloatField(null=True, verbose_name='采购总数量')
|
||||
other_amount = AmountField(default=0, verbose_name='其他费用')
|
||||
total_amount = AmountField(null=True, verbose_name='采购总金额')
|
||||
payment_amount = AmountField(default=0, verbose_name='付款金额')
|
||||
arrears_amount = AmountField(default=0, verbose_name='欠款金额')
|
||||
payment_amount = AmountField(null=True, verbose_name='付款金额')
|
||||
arrears_amount = AmountField(null=True, verbose_name='欠款金额')
|
||||
payment_order = OneToOneField('finance.PaymentOrder', on_delete=PROTECT, null=True,
|
||||
related_name='purchase_order', verbose_name='付款单据')
|
||||
is_void = BooleanField(default=False, verbose_name='作废状态')
|
||||
|
@ -36,7 +36,7 @@ class PurchaseOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'CG' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
number = 'CG' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD').format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
@ -90,7 +90,7 @@ class PurchaseReturnOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'CR' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'CR' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
class Meta:
|
||||
model = PurchaseOrder
|
||||
read_only_fields = ['id', 'warehouse_number', 'warehouse_name', 'supplier_number', 'supplier_name',
|
||||
'handler_name', 'total_amount', 'total_quantity', 'payment_amount', 'arrears_amount',
|
||||
'handler_name', 'total_quantity', 'total_amount', 'payment_amount', 'arrears_amount',
|
||||
'is_void', 'enable_auto_stock_in', 'creator_name', 'create_time']
|
||||
fields = ['number', 'warehouse', 'supplier', 'handler', 'handle_time', 'other_amount', 'remark',
|
||||
'purchase_goods_items', 'payment_account_items', *read_only_fields]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from extensions.routers import *
|
||||
from apps.purchase.views import *
|
||||
|
||||
|
||||
router = BaseRouter()
|
||||
router.register('purchase_orders', PurchaseOrderViewSet, 'purchase_order')
|
||||
urlpatterns = router.urls
|
||||
|
|
|
@ -84,9 +84,9 @@ class PurchaseOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
|
|||
amount_after = NP.minus(amount_before, amount_change)
|
||||
|
||||
finance_flows.append(FinanceFlow(
|
||||
account=payment_account.account, type=FinanceFlow.Type.PAYMENT,
|
||||
amount_before=amount_before, amount_change=amount_change, amount_after=amount_after,
|
||||
payment_order=payment_order, creator=self.user, team=self.team
|
||||
account=account, type=FinanceFlow.Type.PAYMENT, amount_before=amount_before,
|
||||
amount_change=amount_change, amount_after=amount_after, payment_order=payment_order,
|
||||
creator=self.user, team=self.team
|
||||
))
|
||||
|
||||
account.balance_amount = amount_after
|
||||
|
@ -173,8 +173,8 @@ class PurchaseOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
|
|||
amount_after = NP.plus(amount_before, amount_change)
|
||||
|
||||
finance_flows.append(FinanceFlow(
|
||||
account=payment_account.account, type=FinanceFlow.Type.VOID_PAYMENT,
|
||||
amount_before=amount_before, amount_change=amount_change, amount_after=amount_after,
|
||||
account=account, type=FinanceFlow.Type.VOID_PAYMENT, amount_before=amount_before,
|
||||
amount_change=amount_change, amount_after=amount_after,
|
||||
void_payment_order=payment_order, creator=self.user, team=self.team
|
||||
))
|
||||
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
from django_filters.rest_framework import FilterSet
|
||||
from django_filters.filters import *
|
||||
from apps.sales.models import *
|
||||
|
||||
|
||||
class SalesOrderFilter(FilterSet):
|
||||
start_date = DateFilter(field_name='create_time', lookup_expr='gte', label='开始日期')
|
||||
end_date = DateFilter(field_name='create_time', lookup_expr='lt', label='结束日期')
|
||||
|
||||
class Meta:
|
||||
model = SalesOrder
|
||||
fields = ['number', 'warehouse', 'client', 'handler', 'is_void', 'creator',
|
||||
'start_date', 'end_date']
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
'SalesOrderFilter',
|
||||
]
|
||||
|
|
|
@ -10,12 +10,12 @@ class SalesOrder(Model):
|
|||
handler = ForeignKey('system.User', on_delete=PROTECT, related_name='sales_orders', verbose_name='经手人')
|
||||
handle_time = DateTimeField(verbose_name='处理时间')
|
||||
remark = CharField(max_length=256, null=True, blank=True, verbose_name='备注')
|
||||
total_quantity = FloatField(verbose_name='总数量')
|
||||
discount = FloatField(default=100, verbose_name='折扣')
|
||||
total_quantity = FloatField(null=True, verbose_name='总数量')
|
||||
discount = FloatField(default=1, verbose_name='折扣')
|
||||
other_amount = AmountField(default=0, verbose_name='其他费用')
|
||||
total_amount = AmountField(verbose_name='总金额')
|
||||
collection_amount = AmountField(default=0, verbose_name='收款金额')
|
||||
arrears_amount = AmountField(default=0, verbose_name='欠款金额')
|
||||
total_amount = AmountField(null=True, verbose_name='总金额')
|
||||
collection_amount = AmountField(null=True, verbose_name='收款金额')
|
||||
arrears_amount = AmountField(null=True, verbose_name='欠款金额')
|
||||
collection_order = OneToOneField('finance.CollectionOrder', on_delete=PROTECT, null=True,
|
||||
related_name='sales_order', verbose_name='收款单据')
|
||||
is_void = BooleanField(default=False, verbose_name='作废状态')
|
||||
|
@ -37,7 +37,7 @@ class SalesOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'XS' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'XS' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
@ -91,7 +91,7 @@ class SalesReturnOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'SR' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'SR' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
from extensions.permissions import InterfacePermission
|
||||
|
||||
|
||||
__all__ = [
|
||||
class SalesOrderPermission(InterfacePermission):
|
||||
code = 'sales_order'
|
||||
|
||||
|
||||
class SalesReturnOrderPermission(InterfacePermission):
|
||||
code = 'sales_return_order'
|
||||
|
||||
|
||||
__all__ = [
|
||||
'SalesOrderPermission', 'SalesReturnOrderPermission',
|
||||
]
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
from extensions.serializers import *
|
||||
|
||||
|
||||
__all__ = [
|
||||
class NumberResponse(Serializer):
|
||||
number = CharField(label='编号')
|
||||
|
||||
|
||||
__all__ = [
|
||||
'NumberResponse',
|
||||
]
|
||||
|
|
|
@ -1,7 +1,183 @@
|
|||
from extensions.serializers import *
|
||||
from extensions.exceptions import *
|
||||
from apps.sales.models import *
|
||||
from apps.data.models import *
|
||||
from apps.goods.models import *
|
||||
from apps.system.models import *
|
||||
from apps.finance.models import *
|
||||
|
||||
|
||||
class SalesOrderSerializer(BaseSerializer):
|
||||
"""销售单据"""
|
||||
|
||||
class SalesGoodsSerializer(BaseSerializer):
|
||||
"""销售商品"""
|
||||
|
||||
goods_number = CharField(source='goods.number', read_only=True, label='商品编号')
|
||||
goods_name = CharField(source='goods.name', read_only=True, label='商品名称')
|
||||
goods_barcode = CharField(source='goods.barcode', read_only=True, label='商品条码')
|
||||
unit_name = CharField(source='goods.unit.name', read_only=True, label='单位名称')
|
||||
|
||||
class Meta:
|
||||
model = SalesGoods
|
||||
read_only_fields = ['id', 'goods_number', 'goods_name', 'goods_barcode', 'total_amount',
|
||||
'return_quantity', 'unit_name']
|
||||
fields = ['goods', 'sales_quantity', 'sales_price', *read_only_fields]
|
||||
|
||||
def validate_goods(self, instance):
|
||||
instance = self.validate_foreign_key(Goods, instance, message='商品不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'商品[{instance.name}]未激活')
|
||||
return instance
|
||||
|
||||
def validate_sales_quantity(self, value):
|
||||
if value <= 0:
|
||||
raise ValidationError('销售数量小于或等于零')
|
||||
return value
|
||||
|
||||
def validate_sales_price(self, value):
|
||||
if value <= 0:
|
||||
raise ValidationError('销售单价小于或等于零')
|
||||
return value
|
||||
|
||||
class CollectionAccountSerializer(BaseSerializer):
|
||||
"""收款账户"""
|
||||
|
||||
account_number = CharField(source='account.number', read_only=True, label='账户编号')
|
||||
account_name = CharField(source='account.name', read_only=True, label='账户名称')
|
||||
|
||||
class Meta:
|
||||
model = CollectionAccount
|
||||
read_only_fields = ['id', 'account_number', 'account_name']
|
||||
fields = ['account', 'collection_amount', *read_only_fields]
|
||||
|
||||
def validate_account(self, instance):
|
||||
instance = self.validate_foreign_key(Account, instance, message='账户不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'账户[{instance.name}]未激活')
|
||||
return instance
|
||||
|
||||
def validate_collection_amount(self, value):
|
||||
if value <= 0:
|
||||
raise ValidationError('收款金额小于或等于零')
|
||||
return value
|
||||
|
||||
warehouse_number = CharField(source='warehouse.number', read_only=True, label='仓库编号')
|
||||
warehouse_name = CharField(source='warehouse.name', read_only=True, label='仓库名称')
|
||||
client_number = CharField(source='client.number', read_only=True, label='客户编号')
|
||||
client_name = CharField(source='client.name', read_only=True, label='客户名称')
|
||||
handler_name = CharField(source='handler.name', read_only=True, label='经手人名称')
|
||||
creator_name = CharField(source='creator.name', read_only=True, label='创建人名称')
|
||||
sales_goods_items = SalesGoodsSerializer(source='sales_goods_set', many=True, label='销售商品')
|
||||
collection_account_items = CollectionAccountSerializer(source='collection_order.collection_accounts',
|
||||
required=False, many=True, label='收款账户')
|
||||
|
||||
class Meta:
|
||||
model = SalesOrder
|
||||
read_only_fields = ['id', 'warehouse_number', 'warehouse_name', 'client_number', 'client_name',
|
||||
'handler_name', 'total_quantity', 'total_amount', 'collection_amount',
|
||||
'arrears_amount', 'is_void', 'enable_auto_stock_out', 'creator_name', 'create_time']
|
||||
fields = ['number', 'warehouse', 'client', 'handler', 'handle_time', 'discount', 'other_amount', 'remark',
|
||||
'sales_goods_items', 'collection_account_items', *read_only_fields]
|
||||
|
||||
def validate_number(self, value):
|
||||
self.validate_unique({'number': value}, message=f'编号[{value}]已存在')
|
||||
return value
|
||||
|
||||
def validate_warehouse(self, instance):
|
||||
instance = self.validate_foreign_key(Warehouse, instance, message='仓库不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'仓库[{instance.name}]未激活')
|
||||
|
||||
if not instance.is_locked:
|
||||
raise ValidationError(f'仓库[{instance.name}]已锁定')
|
||||
return instance
|
||||
|
||||
def validate_client(self, instance):
|
||||
instance = self.validate_foreign_key(Client, instance, message='客户不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'客户[{instance.name}]未激活')
|
||||
return instance
|
||||
|
||||
def validate_handler(self, instance):
|
||||
instance = self.validate_foreign_key(User, instance, message='经手人不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'经手人[{instance.name}]未激活')
|
||||
return instance
|
||||
|
||||
def validate_other_amount(self, value):
|
||||
if value <= 0:
|
||||
raise ValidationError('其他费用小于或等于零')
|
||||
return value
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
sales_goods_items = validated_data.pop('sales_goods_set')
|
||||
collection_order_item = validated_data.pop('collection_order', {})
|
||||
collection_account_items = collection_order_item.pop('collection_accounts', [])
|
||||
|
||||
validated_data['enable_auto_stock_out'] = self.team.enable_auto_stock_out
|
||||
validated_data['creator'] = self.user
|
||||
sales_order = super().create(validated_data)
|
||||
|
||||
total_sales_quantity = 0
|
||||
total_sales_amount = 0
|
||||
|
||||
# 创建销售商品
|
||||
sales_goods_set = []
|
||||
for sales_goods_item in sales_goods_items:
|
||||
sales_quantity = sales_goods_item['sales_quantity']
|
||||
sales_price = sales_goods_item['sales_price']
|
||||
total_amount = NP.times(sales_quantity, sales_price)
|
||||
sales_goods_set.append(SalesGoods(
|
||||
sales_order=sales_order, goods=sales_goods_item['goods'], sales_quantity=sales_quantity,
|
||||
sales_price=sales_price, total_amount=total_amount, team=self.team
|
||||
))
|
||||
|
||||
total_sales_quantity = NP.plus(total_sales_quantity, sales_quantity)
|
||||
total_sales_amount = NP.plus(total_sales_amount, total_amount)
|
||||
else:
|
||||
SalesGoods.objects.bulk_create(sales_goods_set)
|
||||
total_sales_amount = NP.times(total_sales_amount, sales_order.discount)
|
||||
total_sales_amount = NP.plus(total_sales_amount, sales_order.other_amount)
|
||||
sales_order.total_quantity = total_sales_quantity
|
||||
sales_order.total_amount = total_sales_amount
|
||||
|
||||
total_collection_amount = 0
|
||||
|
||||
# 创建收款单据
|
||||
if collection_account_items:
|
||||
collection_order_number = CollectionOrder.get_number(team=self.team)
|
||||
collection_order_remark = f'销售单据: {sales_order.number}'
|
||||
collection_order = CollectionOrder.objects.create(
|
||||
number=collection_order_number, client=sales_order.client,
|
||||
handler=sales_order.handler, handle_time=sales_order.handle_time,
|
||||
remark=collection_order_remark, creator=self.user, team=self.team
|
||||
)
|
||||
|
||||
# 创建收款账户
|
||||
collection_accounts = []
|
||||
for collection_account_item in collection_account_items:
|
||||
collection_amount = collection_account_item['collection_amount']
|
||||
collection_accounts.append(CollectionAccount(
|
||||
collection_order=collection_order, account=collection_account_item['account'],
|
||||
collection_amount=collection_amount, team=self.team
|
||||
))
|
||||
|
||||
total_collection_amount = NP.plus(total_collection_amount, collection_amount)
|
||||
else:
|
||||
CollectionAccount.objects.bulk_create(collection_accounts)
|
||||
collection_order.total_amount = total_collection_amount
|
||||
collection_order.save(update_fields=['total_amount'])
|
||||
sales_order.collection_order = collection_order
|
||||
|
||||
sales_order.collection_amount = total_collection_amount
|
||||
sales_order.arrears_amount = NP.minus(total_sales_amount, total_collection_amount)
|
||||
sales_order.save(update_fields=['total_quantity', 'total_amount', 'collection_amount',
|
||||
'arrears_amount', 'collection_order'])
|
||||
return sales_order
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
'SalesOrderSerializer',
|
||||
]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from extensions.routers import *
|
||||
from apps.sales.views import *
|
||||
|
||||
|
||||
router = BaseRouter()
|
||||
router.register('sales_orders', SalesOrderViewSet, 'sales_order')
|
||||
urlpatterns = router.urls
|
||||
|
|
|
@ -1,8 +1,192 @@
|
|||
from extensions.permissions import *
|
||||
from extensions.exceptions import *
|
||||
from extensions.viewsets import *
|
||||
from apps.sales.serializers import *
|
||||
from apps.sales.permissions import *
|
||||
from apps.sales.filters import *
|
||||
from apps.sales.schemas import *
|
||||
from apps.sales.models import *
|
||||
from apps.goods.models import *
|
||||
from apps.flow.models import *
|
||||
from apps.stock_out.models import *
|
||||
|
||||
|
||||
class SalesOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateModelMixin):
|
||||
"""销售单据"""
|
||||
|
||||
serializer_class = SalesOrderSerializer
|
||||
permission_classes = [IsAuthenticated, SalesOrderPermission]
|
||||
filterset_class = SalesOrderFilter
|
||||
search_fields = ['number', 'client__number', 'client__name', 'remark']
|
||||
ordering_fields = ['id', 'number', 'total_quantity', 'total_amount', 'create_time']
|
||||
select_related_fields = ['warehouse', 'client', 'handler', 'creator']
|
||||
prefetch_related_fields = ['sales_goods_set', 'sales_goods_set__goods__unit',
|
||||
'payment_order__payment_accounts']
|
||||
queryset = SalesOrder.objects.all()
|
||||
|
||||
@transaction.atomic
|
||||
def perform_create(self, serializer):
|
||||
sales_order = serializer.save()
|
||||
|
||||
# 同步出库
|
||||
if sales_order.enable_auto_stock_out:
|
||||
# 同步库存, 流水
|
||||
inventory_flows = []
|
||||
for sales_goods in sales_order.sales_goods_set.all():
|
||||
inventory = Inventory.objects.get(warehouse=sales_order.warehouse,
|
||||
goods=sales_goods.goods, team=self.team)
|
||||
quantity_before = inventory.total_quantity
|
||||
quantity_change = sales_goods.sales_quantity
|
||||
quantity_after = NP.minus(inventory.total_quantity, sales_goods.sales_quantity)
|
||||
|
||||
inventory_flows.append(InventoryFlow(
|
||||
warehouse=sales_order.warehouse, goods=sales_goods.goods,
|
||||
type=InventoryFlow.Type.SALES, quantity_before=quantity_before,
|
||||
quantity_change=quantity_change, quantity_after=quantity_after,
|
||||
sales_order=sales_order, creator=self.user, team=self.team
|
||||
))
|
||||
|
||||
inventory.total_quantity = quantity_after
|
||||
inventory.save(update_fields=['total_quantity'])
|
||||
else:
|
||||
InventoryFlow.objects.bulk_create(inventory_flows)
|
||||
else:
|
||||
# 创建出库单据
|
||||
stock_out_order_number = StockOutOrder.get_number(team=self.team)
|
||||
stock_out_order = StockOutOrder.objects.create(
|
||||
number=stock_out_order_number, warehouse=sales_order.warehouse,
|
||||
type=StockOutOrder.Type.SALES, sales_order=sales_order, total_quantity=sales_order.total_quantity,
|
||||
creator=self.user, team=self.team
|
||||
)
|
||||
|
||||
# 创建出库商品
|
||||
stock_out_goods_set = []
|
||||
for sales_goods in sales_order.sales_goods_set.all():
|
||||
stock_out_goods_set.append(StockOutGoods(
|
||||
stock_out_order=stock_out_order, goods=sales_goods.goods,
|
||||
stock_out_quantity=sales_goods.sales_quantity, team=self.team
|
||||
))
|
||||
else:
|
||||
StockOutGoods.objects.bulk_create(stock_out_goods_set)
|
||||
|
||||
# 同步欠款
|
||||
client = sales_order.client
|
||||
client.arrears_amount = NP.plus(client.arrears_amount, client.arrears_amount)
|
||||
client.save(update_fields=['arrears_amount'])
|
||||
|
||||
# 同步账户, 流水
|
||||
if collection_order := sales_order.collection_order:
|
||||
finance_flows = []
|
||||
for collection_account in collection_order.collection_accounts.all():
|
||||
account = collection_account.account
|
||||
amount_before = account.balance_amount
|
||||
amount_change = collection_account.collection_amount
|
||||
amount_after = NP.plus(amount_before, amount_change)
|
||||
|
||||
finance_flows.append(FinanceFlow(
|
||||
account=account, type=FinanceFlow.Type.COLLECTION, amount_before=amount_before,
|
||||
amount_change=amount_change, amount_after=amount_after,
|
||||
collection_order=collection_order, creator=self.user, team=self.team
|
||||
))
|
||||
|
||||
account.balance_amount = amount_after
|
||||
account.save(update_fields=['balance_amount'])
|
||||
else:
|
||||
FinanceFlow.objects.bulk_create(finance_flows)
|
||||
|
||||
@extend_schema(responses={200: NumberResponse})
|
||||
@action(detail=False, methods=['get'])
|
||||
def number(self, request, *args, **kwargs):
|
||||
"""获取编号"""
|
||||
|
||||
number = SalesOrder.get_number(self.team)
|
||||
return Response(data={'number': number}, status=status.HTTP_200_OK)
|
||||
|
||||
@transaction.atomic
|
||||
@extend_schema(request=None, responses={200: SalesOrderSerializer})
|
||||
@action(detail=True, methods=['post'])
|
||||
def void(self, request, *args, **kwargs):
|
||||
"""作废"""
|
||||
|
||||
sales_order = self.get_object()
|
||||
if sales_order.is_void:
|
||||
raise ValidationError(f'销售单据[{sales_order.number}]已作废, 无法再次作废')
|
||||
|
||||
# 同步销售单据, 销售商品
|
||||
sales_order.is_void = True
|
||||
sales_order.save(update_fields=['is_void'])
|
||||
sales_order.sales_goods_set.all().update(is_void=True)
|
||||
|
||||
# 同步出库
|
||||
if sales_order.enable_auto_stock_out:
|
||||
# 同步库存, 流水
|
||||
inventory_flows = []
|
||||
for sales_goods in sales_order.sales_goods_set.all():
|
||||
inventory = Inventory.objects.get(warehouse=sales_order.warehouse,
|
||||
goods=sales_goods.goods, team=self.team)
|
||||
quantity_before = inventory.total_quantity
|
||||
quantity_change = sales_goods.sales_quantity
|
||||
quantity_after = NP.plus(inventory.total_quantity, sales_goods.sales_quantity)
|
||||
|
||||
inventory_flows.append(InventoryFlow(
|
||||
warehouse=sales_order.warehouse, goods=sales_goods.goods,
|
||||
type=InventoryFlow.Type.VOID_SALES, quantity_before=quantity_before,
|
||||
quantity_change=quantity_change, quantity_after=quantity_after,
|
||||
void_sales_order=sales_order, creator=self.user, team=self.team
|
||||
))
|
||||
|
||||
inventory.total_quantity = quantity_after
|
||||
inventory.save(update_fields=['total_quantity'])
|
||||
else:
|
||||
InventoryFlow.objects.bulk_create(inventory_flows)
|
||||
else:
|
||||
# 作废出库单据
|
||||
stock_out_order = sales_order.stock_out_order
|
||||
if stock_out_order.total_quantity != stock_out_order.remain_quantity:
|
||||
raise ValidationError(f'销售单据[{sales_order.number}]无法作废, 已存在出库记录')
|
||||
|
||||
stock_out_order.is_void = True
|
||||
stock_out_order.save(update_fields=['is_void'])
|
||||
|
||||
# 作废出库商品
|
||||
stock_out_order.stock_out_goods_set.all().update(is_void=True)
|
||||
|
||||
# 同步欠款
|
||||
client = sales_order.client
|
||||
client.arrears_amount = NP.minus(client.arrears_amount, sales_order.arrears_amount)
|
||||
client.save(update_fields=['arrears_amount'])
|
||||
|
||||
# 同步账户, 流水
|
||||
if collection_order := sales_order.collection_order:
|
||||
# 作废收款单据
|
||||
collection_order.is_void = True
|
||||
collection_order.save(update_fields=['is_void'])
|
||||
|
||||
# 作废收款账号
|
||||
collection_order.collection_accounts.all().update(is_void=True)
|
||||
|
||||
finance_flows = []
|
||||
for collection_account in collection_order.collection_accounts.all():
|
||||
account = collection_account.account
|
||||
amount_before = account.balance_amount
|
||||
amount_change = collection_account.collection_amount
|
||||
amount_after = NP.minus(amount_before, amount_change)
|
||||
|
||||
finance_flows.append(FinanceFlow(
|
||||
account=account, type=FinanceFlow.Type.VOID_PAYMENT, amount_before=amount_before,
|
||||
amount_change=amount_change, amount_after=amount_after,
|
||||
void_collection_order=collection_order, creator=self.user, team=self.team
|
||||
))
|
||||
|
||||
account.balance_amount = amount_after
|
||||
account.save(update_fields=['balance_amount'])
|
||||
else:
|
||||
FinanceFlow.objects.bulk_create(finance_flows)
|
||||
|
||||
serializer = SalesOrderSerializer(instance=sales_order)
|
||||
return Response(data=serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
'SalesOrderViewSet',
|
||||
]
|
||||
|
|
|
@ -38,7 +38,7 @@ class StockCheckOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'PD' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'PD' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class StockInOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'RK' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'RK' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class StockOutOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'CK' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'CK' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
@ -55,7 +55,7 @@ class StockOutGoods(Model):
|
|||
stock_out_order = ForeignKey('stock_out.StockOutOrder', on_delete=CASCADE,
|
||||
related_name='stock_out_goods_set', verbose_name='出库单据')
|
||||
goods = ForeignKey('goods.Goods', on_delete=PROTECT, related_name='stock_out_goods_set', verbose_name='商品')
|
||||
total_quantity = FloatField(verbose_name='出库总数')
|
||||
stock_out_quantity = FloatField(verbose_name='出库总数')
|
||||
remain_quantity = FloatField(default=0, verbose_name='出库剩余数量')
|
||||
is_completed = BooleanField(default=False, verbose_name='完成状态')
|
||||
is_void = BooleanField(default=False, verbose_name='作废状态')
|
||||
|
|
|
@ -30,7 +30,7 @@ class StockTransferOrder(Model):
|
|||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'DB' + pendulum.today(settings.TIME_ZONE) + '0001'
|
||||
number = 'DB' + pendulum.today(settings.TIME_ZONE).format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ def run(*args):
|
|||
team = Team.objects.all().first()
|
||||
with transaction.atomic():
|
||||
Account.objects.create(number='A001', name='默认账户', team=team)
|
||||
Client.objects.create(number='C001', name='默认客户', team=team)
|
||||
Supplier.objects.create(number='S001', name='默认供应商', team=team)
|
||||
|
||||
warehouse = Warehouse.objects.create(number='W001', name='默认仓库', team=team)
|
||||
goods = Goods.objects.create(number='G001', name='商品A', purchase_price=10, retail_price=20,
|
||||
level_price1=20, level_price2=20, level_price3=20, team=team)
|
||||
|
|
Loading…
Reference in a new issue