mirror of
https://github.com/himool/HimoolERP.git
synced 2025-04-03 10:10:17 +08:00
feat: 采购单据
This commit is contained in:
parent
b7447c7e9c
commit
121cb37e05
22 changed files with 115 additions and 48 deletions
apps
data
finance
flow
goods
purchase
sales
stock_check
stock_in
stock_out
stock_transfer
system
documents
extensions
scripts
|
@ -2,5 +2,5 @@ from django.contrib import admin
|
|||
from apps.data.models import *
|
||||
|
||||
|
||||
admin.register([Warehouse, Client, Supplier, Account,
|
||||
ChargeItem, ClientCategory, SupplierCategory, GoodsCategory, GoodsUnit])
|
||||
admin.site.register([Warehouse, Client, Supplier, Account,
|
||||
ChargeItem, ClientCategory, SupplierCategory, GoodsCategory, GoodsUnit])
|
||||
|
|
|
@ -22,7 +22,7 @@ class WarehouseSerializer(BaseSerializer):
|
|||
return value
|
||||
|
||||
def validate_manager(self, instance):
|
||||
instance = self.validate_foreign_key(User, instance)
|
||||
instance = self.validate_foreign_key(User, instance, message='管理员不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'管理员[{instance.name}]未激活')
|
||||
return instance
|
||||
|
@ -47,7 +47,7 @@ class ClientSerializer(BaseSerializer):
|
|||
return value
|
||||
|
||||
def validate_category(self, instance):
|
||||
instance = self.validate_foreign_key(ClientCategory, instance)
|
||||
instance = self.validate_foreign_key(ClientCategory, instance, message='客户分类不存在')
|
||||
return instance
|
||||
|
||||
def create(self, validated_data):
|
||||
|
@ -80,7 +80,7 @@ class SupplierSerializer(BaseSerializer):
|
|||
return value
|
||||
|
||||
def validate_category(self, instance):
|
||||
instance = self.validate_foreign_key(SupplierCategory, instance)
|
||||
instance = self.validate_foreign_key(SupplierCategory, instance, message='供应商分类不存在')
|
||||
return instance
|
||||
|
||||
def create(self, validated_data):
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from apps.finance.models import *
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register([])
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from apps.flow.models import *
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register([])
|
||||
|
|
|
@ -2,4 +2,4 @@ from django.contrib import admin
|
|||
from apps.goods.models import *
|
||||
|
||||
|
||||
admin.register([Goods, Batch, Inventory])
|
||||
admin.site.register([Goods, Batch, Inventory])
|
||||
|
|
|
@ -26,11 +26,11 @@ class GoodsSerializer(BaseSerializer):
|
|||
return value
|
||||
|
||||
def validate_category(self, instance):
|
||||
instance = self.validate_foreign_key(GoodsCategory, instance)
|
||||
instance = self.validate_foreign_key(GoodsCategory, instance, message='商品分类不存在')
|
||||
return instance
|
||||
|
||||
def validate_unit(self, instance):
|
||||
instance = self.validate_foreign_key(GoodsUnit, instance)
|
||||
instance = self.validate_foreign_key(GoodsUnit, instance, message='商品单位不存在')
|
||||
return instance
|
||||
|
||||
@transaction.atomic
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from apps.purchase.models import *
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register([])
|
||||
|
|
|
@ -10,9 +10,9 @@ class PurchaseOrder(Model):
|
|||
handler = ForeignKey('system.User', on_delete=PROTECT, related_name='purchase_orders', verbose_name='经手人')
|
||||
handle_time = DateTimeField(verbose_name='处理时间')
|
||||
remark = CharField(max_length=256, null=True, blank=True, verbose_name='备注')
|
||||
total_quantity = FloatField(verbose_name='采购总数量')
|
||||
total_quantity = FloatField(null=True, verbose_name='采购总数量')
|
||||
other_amount = AmountField(default=0, verbose_name='其他费用')
|
||||
total_amount = AmountField(verbose_name='采购总金额')
|
||||
total_amount = AmountField(null=True, verbose_name='采购总金额')
|
||||
payment_amount = AmountField(default=0, verbose_name='付款金额')
|
||||
arrears_amount = AmountField(default=0, verbose_name='欠款金额')
|
||||
payment_order = OneToOneField('finance.PaymentOrder', on_delete=PROTECT, null=True,
|
||||
|
@ -29,7 +29,16 @@ class PurchaseOrder(Model):
|
|||
|
||||
@classmethod
|
||||
def get_number(cls, team):
|
||||
return
|
||||
start_date, end_date = pendulum.now(), pendulum.tomorrow()
|
||||
instance = cls.objects.filter(team=team, create_time__gte=start_date, create_time__lt=end_date).last()
|
||||
|
||||
try:
|
||||
result = re.match('^(.*?)([1-9]+)$', instance.number)
|
||||
number = result.group(1) + str(int(result.group(2)) + 1)
|
||||
except AttributeError:
|
||||
number = 'CG' + start_date.format('YYYYMMDD') + '0001'
|
||||
|
||||
return number
|
||||
|
||||
|
||||
class PurchaseGoods(Model):
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
from extensions.serializers import *
|
||||
|
||||
|
||||
__all__ = [
|
||||
class NumberResponse(Serializer):
|
||||
number = CharField(label='编号')
|
||||
|
||||
|
||||
__all__ = [
|
||||
'NumberResponse',
|
||||
]
|
||||
|
|
|
@ -25,7 +25,7 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
fields = ['goods', 'purchase_quantity', 'purchase_price', *read_only_fields]
|
||||
|
||||
def validate_goods(self, instance):
|
||||
instance = self.validate_foreign_key(Goods, instance)
|
||||
instance = self.validate_foreign_key(Goods, instance, message='商品不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'商品[{instance.name}]未激活')
|
||||
return instance
|
||||
|
@ -52,9 +52,9 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
fields = ['account', 'payment_amount', *read_only_fields]
|
||||
|
||||
def validate_account(self, instance):
|
||||
instance = self.validate_foreign_key(Account, instance)
|
||||
instance = self.validate_foreign_key(Account, instance, message='账户不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'结算账户[{instance.name}]未激活')
|
||||
raise ValidationError(f'账户[{instance.name}]未激活')
|
||||
return instance
|
||||
|
||||
def validate_payment_amount(self, value):
|
||||
|
@ -85,7 +85,7 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
return value
|
||||
|
||||
def validate_warehouse(self, instance):
|
||||
instance = self.validate_foreign_key(Warehouse, instance)
|
||||
instance = self.validate_foreign_key(Warehouse, instance, message='仓库不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'仓库[{instance.name}]未激活')
|
||||
|
||||
|
@ -94,13 +94,13 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
return instance
|
||||
|
||||
def validate_supplier(self, instance):
|
||||
instance = self.validate_foreign_key(Supplier, instance)
|
||||
instance = self.validate_foreign_key(Supplier, 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)
|
||||
instance = self.validate_foreign_key(User, instance, message='经手人不存在')
|
||||
if not instance.is_active:
|
||||
raise ValidationError(f'经手人[{instance.name}]未激活')
|
||||
return instance
|
||||
|
@ -112,11 +112,10 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
purchase_goods_items = validated_data.pop('purchase_goods_items')
|
||||
payment_account_items = validated_data.pop('payment_account_items', None)
|
||||
print(purchase_goods_items)
|
||||
print(payment_account_items)
|
||||
|
||||
purchase_goods_items = validated_data.pop('purchase_goods_set')
|
||||
payment_order_item = validated_data.pop('payment_order', {})
|
||||
payment_account_items = payment_order_item.pop('payment_accounts', [])
|
||||
|
||||
validated_data['enable_auto_stock_in'] = self.team.enable_auto_stock_in
|
||||
validated_data['creator'] = self.user
|
||||
purchase_order = super().create(validated_data)
|
||||
|
@ -144,6 +143,8 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
purchase_order.total_quantity = total_purchase_quantity
|
||||
purchase_order.total_amount = total_purchase_amount
|
||||
|
||||
total_payment_amount = 0
|
||||
|
||||
# 创建付款单据
|
||||
if payment_account_items:
|
||||
payment_order_number = PaymentOrder.get_number(team=self.team)
|
||||
|
@ -154,8 +155,6 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
remark=payment_order_remark, creator=self.user, team=self.team
|
||||
)
|
||||
|
||||
total_payment_amount = 0
|
||||
|
||||
# 创建付款账户
|
||||
payment_accounts = []
|
||||
for payment_account_item in payment_account_items:
|
||||
|
@ -170,12 +169,12 @@ class PurchaseOrderSerializer(BaseSerializer):
|
|||
PaymentAccount.objects.bulk_create(payment_accounts)
|
||||
payment_order.total_amount = total_payment_amount
|
||||
payment_order.save(update_fields=['total_amount'])
|
||||
purchase_order.payment_amount = total_payment_amount
|
||||
purchase_order.arrears_amount = NP.minus(total_purchase_amount, total_payment_amount)
|
||||
purchase_order.payment_order = payment_order
|
||||
|
||||
purchase_order = purchase_order.save(update_fields=['total_quantity', 'total_amount', 'payment_amount',
|
||||
'arrears_amount', 'payment_order'])
|
||||
purchase_order.payment_amount = total_payment_amount
|
||||
purchase_order.arrears_amount = NP.minus(total_purchase_amount, total_payment_amount)
|
||||
purchase_order.save(update_fields=['total_quantity', 'total_amount', 'payment_amount',
|
||||
'arrears_amount', 'payment_order'])
|
||||
return purchase_order
|
||||
|
||||
|
||||
|
|
|
@ -17,11 +17,19 @@ class PurchaseOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, Crea
|
|||
search_fields = ['number', 'supplier__number', 'supplier__name', 'remark']
|
||||
ordering_fields = ['id', 'number', 'total_quantity', 'total_amount', 'create_time']
|
||||
ordering = ['-number', 'id']
|
||||
select_related_fields = ['warehouse', 'supplier', 'handler', 'creator',
|
||||
'purchase_goods_set__goods__unit']
|
||||
prefetch_related_fields = ['purchase_goods_set', 'payment_order__payment_accounts']
|
||||
select_related_fields = ['warehouse', 'supplier', 'handler', 'creator']
|
||||
prefetch_related_fields = ['purchase_goods_set', 'purchase_goods_set__goods__unit',
|
||||
'payment_order__payment_accounts']
|
||||
queryset = PurchaseOrder.objects.all()
|
||||
|
||||
@extend_schema(responses={200: NumberResponse})
|
||||
@action(detail=False, methods=['get'])
|
||||
def number(self, request, *args, **kwargs):
|
||||
"""获取编号"""
|
||||
|
||||
number = PurchaseOrder.get_number(self.team)
|
||||
return Response(data={'number': number}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
__all__ = [
|
||||
'PurchaseOrderViewSet',
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from apps.sales.models import *
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register([])
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from apps.stock_check.models import *
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register([])
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from apps.stock_in.models import *
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register([])
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from apps.stock_out.models import *
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register([])
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from apps.stock_out.models import *
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register([])
|
||||
|
|
|
@ -2,4 +2,4 @@ from django.contrib import admin
|
|||
from apps.system.models import *
|
||||
|
||||
|
||||
admin.register([Team, PermissionType, Permission, Role, User])
|
||||
admin.site.register([Team, PermissionType, Permission, Role, User])
|
||||
|
|
|
@ -40,7 +40,7 @@ class UserSerializer(BaseSerializer):
|
|||
return value
|
||||
|
||||
def validate_roles(self, instances):
|
||||
instances = self.validate_foreign_key_set(Role, instances)
|
||||
instances = self.validate_foreign_key_set(Role, instances, message='角色不存在')
|
||||
return instances
|
||||
|
||||
def create(self, validated_data):
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
http://127.0.0.1:8000/api/schema/swagger-ui/
|
||||
http://127.0.0.1:8000/api/schema/redoc/
|
||||
http://127.0.0.1:8000/api/
|
||||
http://127.0.0.1:8000/admin/
|
||||
```
|
||||
|
||||
## 构建
|
||||
|
@ -21,6 +22,8 @@ python manage.py shell_plus
|
|||
```
|
||||
python tools/create_configs.py
|
||||
python tools/rebuild_database.py
|
||||
python manage.py createsuperuser
|
||||
python manage.py runscript init_permission
|
||||
python manage.py runscript create_user
|
||||
python manage.py runscript create_test_data
|
||||
```
|
||||
|
|
|
@ -28,8 +28,6 @@ class BaseSerializer(ModelSerializer):
|
|||
if instance:
|
||||
if not (instance := model.objects.filter(id=instance.id, team=self.team).first()):
|
||||
raise ValidationError(message)
|
||||
instance.validate()
|
||||
|
||||
return instance
|
||||
|
||||
def validate_foreign_key_set(self, model, instances, message):
|
||||
|
@ -39,10 +37,6 @@ class BaseSerializer(ModelSerializer):
|
|||
|
||||
if len(instance_ids) != len(instances):
|
||||
raise ValidationError(message)
|
||||
|
||||
for instance in instances:
|
||||
instance.validate()
|
||||
|
||||
return instances
|
||||
|
||||
def validate_unique(self, fields, message):
|
||||
|
|
15
scripts/create_test_data.py
Normal file
15
scripts/create_test_data.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from django.db import transaction
|
||||
from apps.data.models import *
|
||||
from apps.goods.models import *
|
||||
from apps.system.models import *
|
||||
|
||||
|
||||
def run(*args):
|
||||
team = Team.objects.all().first()
|
||||
with transaction.atomic():
|
||||
Account.objects.create(number='A001', 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)
|
||||
Inventory.objects.create(warehouse=warehouse, goods=goods, team=team)
|
19
scripts/create_user.py
Normal file
19
scripts/create_user.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
from django.contrib.auth.hashers import make_password
|
||||
from django.db import transaction
|
||||
from apps.system.models import *
|
||||
from apps.data.models import *
|
||||
import pendulum
|
||||
|
||||
|
||||
def run(*args):
|
||||
number = input('编号: ')
|
||||
username = input('用户名: ')
|
||||
password = input('密码: ')
|
||||
name = input('名称: ')
|
||||
activation_days = input('激活天数: ')
|
||||
expiry_time = pendulum.now().add(days=float(activation_days))
|
||||
|
||||
with transaction.atomic():
|
||||
team = Team.objects.create(number=number, expiry_time=expiry_time)
|
||||
User.objects.create(team=team, username=username, password=make_password(password),
|
||||
name=name, is_manager=True)
|
Loading…
Add table
Reference in a new issue