GoodERP
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

175 líneas
6.7KB

  1. # Copyright 2016 上海开阖软件有限公司 (http://www.osbzr.com)
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  3. from odoo import api, fields, models, _
  4. from odoo.exceptions import UserError
  5. AVAILABLE_PRIORITIES = [
  6. ('0', 'E'),
  7. ('1', 'D'),
  8. ('2', 'C'),
  9. ('3', 'B'),
  10. ('4', 'A'),
  11. ]
  12. class Partner(models.Model):
  13. '''
  14. odoo 中 res.partner 被过度使用,导致很多针对客户的控制逻辑很难实现。
  15. GoodERP采用了全新的业务伙伴对象。
  16. c_category_id 非空 业务伙伴是客户。
  17. s_category_id 非空 业务伙伴是供应商。
  18. '''
  19. _name = 'partner'
  20. _description = '业务伙伴'
  21. _inherit = ['mail.thread', 'mail.activity.mixin']
  22. code = fields.Char('编号')
  23. name = fields.Char('名称', required=True,)
  24. display_name = fields.Char(
  25. '显示名称',
  26. compute='_compute_partner_display_name',
  27. store=False,
  28. readonly=True,
  29. )
  30. @api.depends('code', 'name')
  31. def _compute_partner_display_name(self):
  32. for partner in self:
  33. if partner.code:
  34. partner.display_name = f'[{partner.code}]{partner.name}'
  35. else:
  36. partner.display_name = partner.name
  37. main_mobile = fields.Char('主要联系方式', required=False,)
  38. main_address = fields.Char('注册地址 电话')
  39. priority = fields.Selection(AVAILABLE_PRIORITIES,
  40. '客户重要性', default='0')
  41. supp_priority = fields.Selection(AVAILABLE_PRIORITIES,
  42. '供应商重要性', default='0')
  43. c_category_id = fields.Many2one('core.category', '客户类别',
  44. ondelete='restrict',
  45. domain=[('type', '=', 'customer')])
  46. s_category_id = fields.Many2one('core.category', '供应商类别',
  47. ondelete='restrict',
  48. domain=[('type', '=', 'supplier')])
  49. receivable = fields.Float('应收余额', readonly=True,
  50. copy=False,
  51. digits='Amount')
  52. payable = fields.Float('应付余额', readonly=True,
  53. copy=False,
  54. digits='Amount')
  55. tax_num = fields.Char('税务登记号')
  56. tax_rate = fields.Float('税率(%)',
  57. help='业务伙伴税率')
  58. bank_name = fields.Char('开户行')
  59. bic = fields.Char('行号')
  60. bank_num = fields.Char('银行账号')
  61. credit_limit = fields.Float(
  62. string='信用额度',
  63. tracking=True,
  64. help='客户购买商品时,一般本次发货金额+客户应收余额要小于客户信用额度')
  65. recon_day = fields.Integer("对账日")
  66. active = fields.Boolean('启用', default=True)
  67. company_id = fields.Many2one(
  68. 'res.company',
  69. string='公司',
  70. change_default=True,
  71. default=lambda self: self.env.company)
  72. tag_ids = fields.Many2many(
  73. 'core.value',
  74. ondelete='restrict',
  75. string='标签',
  76. domain=[('type', '=', 'partner_tag')])
  77. channel_id = fields.Many2one(
  78. 'core.value',
  79. string='渠道',
  80. ondelete='restrict',
  81. domain=[('type', '=', 'channel')],
  82. context={'type': 'channel'})
  83. source = fields.Char('来源')
  84. note = fields.Text('备注')
  85. main_contact = fields.Char('主联系人')
  86. responsible_id = fields.Many2one(
  87. 'res.users',
  88. tracking=True,
  89. ondelete='cascade',
  90. string='负责人员')
  91. share_id = fields.Many2one('res.users',
  92. '共享人员')
  93. pay_method = fields.Many2one('pay.method',
  94. string='付款方式',
  95. tracking=True,
  96. ondelete='restrict')
  97. date_qualify = fields.Date('资质到期日期')
  98. days_qualify = fields.Float('资质到期天数',
  99. compute='compute_days_qualify',
  100. store=True,
  101. help='当天到资质到期日期的天数差',
  102. )
  103. _sql_constraints = [
  104. ('name_uniq', 'unique(name)', '业务伙伴不能重名')
  105. ]
  106. @api.constrains('name', 'c_category_id', 's_category_id')
  107. def _check_category_exists(self):
  108. # 客户 或 供应商 类别有一个必输
  109. if self.name and not self.s_category_id and not self.c_category_id:
  110. raise UserError('请选择类别')
  111. @api.model
  112. def name_search(self, name='', args=None, operator='ilike', limit=100):
  113. """
  114. 在many2one字段中支持按编号搜索
  115. """
  116. args = args or []
  117. if name:
  118. res_id = self.search([('code', '=', name)])
  119. if res_id:
  120. return [(record.id, record.display_name)
  121. for record in res_id]
  122. args.append(('code', 'ilike', name))
  123. partners = self.search(args)
  124. if partners:
  125. return [(record.id, record.display_name)
  126. for record in partners]
  127. else:
  128. args.remove(('code', 'ilike', name))
  129. return super(Partner, self).name_search(name=name,
  130. args=args,
  131. operator=operator,
  132. limit=limit)
  133. def write(self, vals):
  134. # 业务伙伴应收/应付余额不为0时,不允许取消对应的客户/供应商身份
  135. if 'c_category_id' in list(vals.keys()) and \
  136. self.c_category_id and not vals.get('c_category_id') \
  137. and self.receivable != 0:
  138. raise UserError('该客户应收余额不为0,不能取消客户类型')
  139. if 's_category_id' in list(vals.keys()) and \
  140. self.s_category_id and not vals.get('s_category_id') \
  141. and self.payable != 0:
  142. raise UserError('该供应商应付余额不为0,不能取消供应商类型')
  143. return super(Partner, self).write(vals)
  144. def copy(self, default=None):
  145. ''' 避免复制时名称重复 '''
  146. if default is None:
  147. default = {}
  148. if 'name' not in default:
  149. default.update(name=_('%s (copy)') % (self.name))
  150. return super().copy(default=default)
  151. @api.depends('date_qualify')
  152. def compute_days_qualify(self):
  153. for partner in self:
  154. """计算当天距离资质到期日期的天数"""
  155. day = 0
  156. if partner.date_qualify:
  157. day = (
  158. partner.date_qualify - fields.Date.context_today(self)
  159. ).days
  160. partner.days_qualify = day
上海开阖软件有限公司 沪ICP备12045867号-1