221 lines
8.1 KiB
Python
221 lines
8.1 KiB
Python
from django.db import transaction
|
|
from rest_framework import serializers
|
|
|
|
from .models import (
|
|
Account,
|
|
CompanySettings,
|
|
Employee,
|
|
Invoice,
|
|
InvoiceLine,
|
|
Party,
|
|
Payslip,
|
|
Product,
|
|
TreasuryTxn,
|
|
Voucher,
|
|
VoucherLine,
|
|
)
|
|
|
|
|
|
class AccountSerializer(serializers.ModelSerializer):
|
|
parentId = serializers.PrimaryKeyRelatedField(
|
|
source='parent', queryset=Account.objects.all(), allow_null=True, required=False
|
|
)
|
|
isGroup = serializers.BooleanField(source='is_group', required=False)
|
|
openingBalance = serializers.FloatField(source='opening_balance', required=False)
|
|
|
|
class Meta:
|
|
model = Account
|
|
fields = ['id', 'code', 'name', 'type', 'parentId', 'isGroup', 'openingBalance']
|
|
|
|
|
|
class PartySerializer(serializers.ModelSerializer):
|
|
economicCode = serializers.CharField(source='economic_code', required=False, allow_blank=True)
|
|
openingBalance = serializers.FloatField(source='opening_balance', required=False)
|
|
|
|
class Meta:
|
|
model = Party
|
|
fields = ['id', 'kind', 'name', 'phone', 'economicCode', 'address', 'openingBalance']
|
|
|
|
|
|
class ProductSerializer(serializers.ModelSerializer):
|
|
salePrice = serializers.FloatField(source='sale_price', required=False)
|
|
purchasePrice = serializers.FloatField(source='purchase_price', required=False)
|
|
reorderLevel = serializers.FloatField(source='reorder_level', required=False)
|
|
|
|
class Meta:
|
|
model = Product
|
|
fields = ['id', 'code', 'name', 'unit', 'salePrice', 'purchasePrice', 'stock', 'reorderLevel']
|
|
|
|
|
|
class VoucherLineSerializer(serializers.ModelSerializer):
|
|
# Lenient: accepts client-generated ids (ignored on write, recreated server-side).
|
|
id = serializers.CharField(required=False)
|
|
accountId = serializers.PrimaryKeyRelatedField(source='account', queryset=Account.objects.all())
|
|
|
|
class Meta:
|
|
model = VoucherLine
|
|
fields = ['id', 'accountId', 'description', 'debit', 'credit']
|
|
|
|
|
|
class VoucherSerializer(serializers.ModelSerializer):
|
|
lines = VoucherLineSerializer(many=True)
|
|
|
|
class Meta:
|
|
model = Voucher
|
|
fields = ['id', 'number', 'date', 'description', 'status', 'source', 'lines']
|
|
|
|
@transaction.atomic
|
|
def create(self, validated_data):
|
|
lines = validated_data.pop('lines', [])
|
|
voucher = Voucher.objects.create(**validated_data)
|
|
for line in lines:
|
|
line.pop('id', None)
|
|
VoucherLine.objects.create(voucher=voucher, **line)
|
|
return voucher
|
|
|
|
@transaction.atomic
|
|
def update(self, instance, validated_data):
|
|
lines = validated_data.pop('lines', None)
|
|
for attr, value in validated_data.items():
|
|
setattr(instance, attr, value)
|
|
instance.save()
|
|
if lines is not None:
|
|
instance.lines.all().delete()
|
|
for line in lines:
|
|
line.pop('id', None)
|
|
VoucherLine.objects.create(voucher=instance, **line)
|
|
return instance
|
|
|
|
|
|
class InvoiceLineSerializer(serializers.ModelSerializer):
|
|
# Lenient: accepts client-generated ids (ignored on write, recreated server-side).
|
|
id = serializers.CharField(required=False)
|
|
productId = serializers.PrimaryKeyRelatedField(
|
|
source='product', queryset=Product.objects.all(), allow_null=True, required=False
|
|
)
|
|
unitPrice = serializers.FloatField(source='unit_price', required=False)
|
|
taxRate = serializers.FloatField(source='tax_rate', required=False)
|
|
|
|
class Meta:
|
|
model = InvoiceLine
|
|
fields = ['id', 'productId', 'quantity', 'unitPrice', 'discount', 'taxRate']
|
|
|
|
|
|
class InvoiceSerializer(serializers.ModelSerializer):
|
|
partyId = serializers.PrimaryKeyRelatedField(
|
|
source='party', queryset=Party.objects.all(), allow_null=True, required=False
|
|
)
|
|
lines = InvoiceLineSerializer(many=True)
|
|
|
|
class Meta:
|
|
model = Invoice
|
|
fields = ['id', 'kind', 'number', 'partyId', 'date', 'status', 'note', 'lines']
|
|
|
|
@transaction.atomic
|
|
def create(self, validated_data):
|
|
lines = validated_data.pop('lines', [])
|
|
invoice = Invoice.objects.create(**validated_data)
|
|
for line in lines:
|
|
line.pop('id', None)
|
|
InvoiceLine.objects.create(invoice=invoice, **line)
|
|
return invoice
|
|
|
|
@transaction.atomic
|
|
def update(self, instance, validated_data):
|
|
lines = validated_data.pop('lines', None)
|
|
for attr, value in validated_data.items():
|
|
setattr(instance, attr, value)
|
|
instance.save()
|
|
if lines is not None:
|
|
instance.lines.all().delete()
|
|
for line in lines:
|
|
line.pop('id', None)
|
|
InvoiceLine.objects.create(invoice=instance, **line)
|
|
return instance
|
|
|
|
|
|
class TreasuryTxnSerializer(serializers.ModelSerializer):
|
|
partyId = serializers.PrimaryKeyRelatedField(
|
|
source='party', queryset=Party.objects.all(), allow_null=True, required=False
|
|
)
|
|
|
|
class Meta:
|
|
model = TreasuryTxn
|
|
fields = ['id', 'number', 'kind', 'method', 'date', 'partyId', 'amount', 'reference', 'description']
|
|
|
|
|
|
class EmployeeSerializer(serializers.ModelSerializer):
|
|
baseSalary = serializers.FloatField(source='base_salary', required=False)
|
|
insuranceNo = serializers.CharField(source='insurance_no', required=False, allow_blank=True)
|
|
hireDate = serializers.DateField(source='hire_date', required=False, allow_null=True)
|
|
|
|
class Meta:
|
|
model = Employee
|
|
fields = ['id', 'code', 'name', 'position', 'baseSalary', 'insuranceNo', 'hireDate', 'active']
|
|
|
|
|
|
class PayslipSerializer(serializers.ModelSerializer):
|
|
employeeId = serializers.PrimaryKeyRelatedField(source='employee', queryset=Employee.objects.all())
|
|
baseSalary = serializers.FloatField(source='base_salary', required=False)
|
|
|
|
class Meta:
|
|
model = Payslip
|
|
fields = [
|
|
'id', 'employeeId', 'period', 'baseSalary', 'overtime', 'bonus',
|
|
'deductions', 'insurance', 'tax',
|
|
]
|
|
|
|
|
|
class CompanySettingsSerializer(serializers.ModelSerializer):
|
|
economicCode = serializers.CharField(source='economic_code', required=False, allow_blank=True)
|
|
fiscalYear = serializers.CharField(source='fiscal_year', required=False, allow_blank=True)
|
|
baseCurrency = serializers.CharField(source='base_currency', required=False, allow_blank=True)
|
|
taxRate = serializers.FloatField(source='tax_rate', required=False)
|
|
voucherAccounts = serializers.SerializerMethodField()
|
|
|
|
_MAPPING_FIELDS = {
|
|
'bankAccountId': 'bank_account_id',
|
|
'ownerPayableAccountId': 'owner_payable_account_id',
|
|
'customerPayableAccountId': 'customer_payable_account_id',
|
|
'ownerShareAccountId': 'owner_share_account_id',
|
|
'salesIncomeAccountId': 'sales_income_account_id',
|
|
}
|
|
|
|
class Meta:
|
|
model = CompanySettings
|
|
fields = [
|
|
'name', 'economicCode', 'fiscalYear', 'baseCurrency',
|
|
'taxRate', 'address', 'phone', 'voucherAccounts',
|
|
]
|
|
|
|
def get_voucherAccounts(self, obj):
|
|
def to_id(value):
|
|
return str(value) if value else ''
|
|
|
|
return {
|
|
'bankAccountId': to_id(obj.bank_account_id),
|
|
'ownerPayableAccountId': to_id(obj.owner_payable_account_id),
|
|
'customerPayableAccountId': to_id(obj.customer_payable_account_id),
|
|
'ownerShareAccountId': to_id(obj.owner_share_account_id),
|
|
'salesIncomeAccountId': to_id(obj.sales_income_account_id),
|
|
}
|
|
|
|
def _apply_voucher_accounts(self, instance):
|
|
mapping = self.initial_data.get('voucherAccounts')
|
|
if not isinstance(mapping, dict):
|
|
return
|
|
valid_ids = {str(v) for v in Account.objects.values_list('id', flat=True)}
|
|
for camel_key, model_attr in self._MAPPING_FIELDS.items():
|
|
if camel_key not in mapping:
|
|
continue
|
|
raw = mapping.get(camel_key)
|
|
setattr(instance, model_attr, raw if raw in valid_ids else None)
|
|
|
|
@transaction.atomic
|
|
def update(self, instance, validated_data):
|
|
for attr, value in validated_data.items():
|
|
setattr(instance, attr, value)
|
|
self._apply_voucher_accounts(instance)
|
|
instance.save()
|
|
return instance
|