1
0
forked from erp-dev/erp

feat: BalanceChangeRecord

This commit is contained in:
2025-12-01 15:22:59 +08:00
parent 9acc4e14fc
commit a3b4af2602
8 changed files with 359 additions and 14 deletions

View File

@@ -462,3 +462,89 @@ class CustomerBalance(ModelBase):
verbose_name = '客户余额'
verbose_name_plural = '客户余额'
unique_together = ('merchant', 'customer')
class BalanceChangeTargetEnum(models.IntegerChoices):
SUPPLIER = 1, '供应商'
CUSTOMER = 2, '客户'
class BalanceChangeSourceEnum(models.IntegerChoices):
PURCHASE_ORDER = 1, '采购单'
SALES_ORDER = 2, '销售单'
PAYMENT_ORDER = 3, '付款单'
RECEIPT_ORDER = 4, '收款单'
class BalanceChangeDirectionEnum(models.IntegerChoices):
INCREASE = 1, '增加'
DECREASE = 2, '减少'
class BalanceChangeRecord(ModelBase):
merchant = models.ForeignKey(
basic_info_models.Merchant,
on_delete=models.PROTECT,
related_name='balance_change_records',
verbose_name='所属商户',
)
supplier = models.ForeignKey(
basic_info_models.Supplier,
on_delete=models.PROTECT,
related_name='balance_change_records',
verbose_name='供应商',
null=True,
blank=True,
)
customer = models.ForeignKey(
basic_info_models.Customer,
on_delete=models.PROTECT,
related_name='balance_change_records',
verbose_name='客户',
null=True,
blank=True,
)
target_type = models.IntegerField(
choices=BalanceChangeTargetEnum.choices,
verbose_name='业务主体类型',
)
source_type = models.IntegerField(
choices=BalanceChangeSourceEnum.choices,
verbose_name='来源业务类型',
)
source_id = models.BigIntegerField(verbose_name='来源业务ID')
delta = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='变动金额')
direction = models.IntegerField(
choices=BalanceChangeDirectionEnum.choices,
verbose_name='方向',
)
balance_before = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='变动前余额')
balance_after = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='变动后余额')
request_id = models.CharField(max_length=64, null=True, blank=True, verbose_name='幂等请求ID')
remarks = models.TextField(blank=True, null=True, verbose_name='备注')
extra_meta = models.JSONField(default=dict, blank=True, verbose_name='扩展信息')
offset_to = models.BigIntegerField(null=True, blank=True, verbose_name='冲抵目标ID')
offset_at = models.DateTimeField(null=True, blank=True, verbose_name='冲抵时间')
offset_id = models.BigIntegerField(null=True, blank=True, verbose_name='冲抵来源ID')
cancelled = models.BooleanField(default=False, verbose_name='已被冲抵')
cancelled_at = models.DateTimeField(null=True, blank=True, verbose_name='被冲抵时间')
class Meta:
verbose_name = '余额变动记录'
verbose_name_plural = '余额变动记录'
indexes = [
models.Index(fields=['merchant', 'source_type', 'source_id'], name='balance_change_source_idx'),
]
constraints = [
models.CheckConstraint(
check=(
(models.Q(supplier__isnull=False, customer__isnull=True))
| (models.Q(supplier__isnull=True, customer__isnull=False))
),
name='balance_change_single_counterparty',
),
]
def __str__(self):
counterparty = self.supplier or self.customer
return f'余额变动 {self.id} - {counterparty}'