You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
19 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. import base64
  2. from odoo import api, fields, models
  3. TYPE_MAP = {
  4. 'subscription': 'subscribed',
  5. 'transfer': 'transfered',
  6. 'sell_back': 'resold'
  7. }
  8. REPORT_DIC = {
  9. 'subscription': (
  10. 'easy_my_coop_taxshelter_report.action_tax_shelter_subscription_report',
  11. 'Tax Shelter Subscription'
  12. ),
  13. 'shares': (
  14. 'easy_my_coop_taxshelter_report.action_tax_shelter_shares_report',
  15. 'Tax Shelter Shares'
  16. )
  17. }
  18. class TaxShelterDeclaration(models.Model):
  19. _name = "tax.shelter.declaration"
  20. _description = "Tax Shelter Declaration"
  21. name = fields.Char(string='Declaration year', required=True)
  22. fiscal_year = fields.Char(String="Fiscal year", required=True)
  23. tax_shelter_certificates = fields.One2many('tax.shelter.certificate',
  24. 'declaration_id',
  25. string='Tax shelter certificates',
  26. readonly=True)
  27. date_from = fields.Date(string='Date from', required=True)
  28. date_to = fields.Date(string='Date to', required=True)
  29. month_from = fields.Char(String='Month from', required=True)
  30. month_to = fields.Char(String='Month to', required=True)
  31. tax_shelter_percentage = fields.Selection([('30', '30%'),
  32. ('45', '45%')],
  33. string='Tax Shelter percentage',
  34. required=True)
  35. state = fields.Selection([('draft', 'Draft'),
  36. ('computed', 'Computed'),
  37. ('validated', 'Validated')],
  38. string='State', required=True, default="draft")
  39. company_id = fields.Many2one('res.company', string='Company',
  40. required=True,
  41. change_default=True, readonly=True,
  42. default=lambda self: self.env['res.company']._company_default_get())
  43. tax_shelter_capital_limit = fields.Float(string="Tax shelter capital limit",
  44. required=True)
  45. previously_subscribed_capital = fields.Float(String="Capital previously subscribed",
  46. readonly=True)
  47. excluded_cooperator = fields.Many2many('res.partner',
  48. string="Excluded cooperator",
  49. domain=[('cooperator', '=', True)],
  50. help="If these cooperator have"
  51. " subscribed share during the time"
  52. " frame of this Tax Shelter "
  53. "Declaration. They will be marked "
  54. "as non eligible")
  55. def _excluded_from_declaration(self, entry):
  56. if entry.date >= self.date_from and entry.date <= self.date_to:
  57. declaration = self
  58. else:
  59. declaration = self.search([('date_from', '<=', entry.date),
  60. ('date_to', '>=', entry.date)])
  61. if entry.partner_id.id in declaration.excluded_cooperator.ids:
  62. return True
  63. return False
  64. def _prepare_line(self, certificate, entry, ongoing_capital_sub, excluded):
  65. line_vals = {}
  66. line_vals['tax_shelter_certificate'] = certificate.id
  67. line_vals['share_type'] = entry.share_product_id.id
  68. line_vals['share_short_name'] = entry.share_short_name
  69. line_vals['share_unit_price'] = entry.share_unit_price
  70. line_vals['quantity'] = entry.quantity
  71. line_vals['transaction_date'] = entry.date
  72. line_vals['type'] = TYPE_MAP[entry.type]
  73. if entry.type == 'subscription':
  74. if not excluded:
  75. capital_after_sub = ongoing_capital_sub + entry.total_amount_line
  76. else:
  77. capital_after_sub = ongoing_capital_sub
  78. line_vals['capital_before_sub'] = ongoing_capital_sub
  79. line_vals['capital_after_sub'] = capital_after_sub
  80. line_vals['capital_limit'] = self.tax_shelter_capital_limit
  81. if ongoing_capital_sub < self.tax_shelter_capital_limit and not excluded:
  82. line_vals['tax_shelter'] = True
  83. return line_vals
  84. def _compute_certificates(self, entries, partner_certificate):
  85. ongoing_capital_sub = 0.0
  86. for entry in entries:
  87. certificate = partner_certificate.get(entry.partner_id.id, False)
  88. if not certificate:
  89. # create a certificate for this cooperator
  90. cert_vals = {}
  91. cert_vals['declaration_id'] = self.id
  92. cert_vals['partner_id'] = entry.partner_id.id
  93. cert_vals['cooperator_number'] = entry.partner_id.cooperator_register_number
  94. certificate = self.env['tax.shelter.certificate'].create(cert_vals)
  95. partner_certificate[entry.partner_id.id] = certificate
  96. excluded = self._excluded_from_declaration(entry)
  97. line_vals = self._prepare_line(certificate, entry, ongoing_capital_sub, excluded)
  98. certificate.write({'lines': [(0, 0, line_vals)]})
  99. if entry.type == 'subscription' and not excluded:
  100. ongoing_capital_sub += entry.total_amount_line
  101. return partner_certificate
  102. @api.one
  103. def compute_declaration(self):
  104. entries = self.env['subscription.register'].search([
  105. ('partner_id.is_company', '=', False),
  106. ('date', '<=', self.date_to),
  107. ('type', 'in', ['subscription',
  108. 'sell_back',
  109. 'transfer'])
  110. ])
  111. subscriptions = entries.filtered((lambda r: r.type == 'subscription' and r.date < self.date_from)) #noqa
  112. cap_prev_sub = 0.0
  113. for subscription in subscriptions:
  114. cap_prev_sub += subscription.total_amount_line
  115. self.previously_subscribed_capital = cap_prev_sub
  116. partner_cert = {}
  117. partner_cert = self._compute_certificates(entries, partner_cert)
  118. self.state = 'computed'
  119. @api.one
  120. def validate_declaration(self):
  121. self.tax_shelter_certificates.write({'state': 'validated'})
  122. self.state = 'validated'
  123. @api.one
  124. def reset_declaration(self):
  125. if not self.state == 'validated':
  126. self.tax_shelter_certificates.unlink()
  127. self.state = 'draft'
  128. class TaxShelterCertificate(models.Model):
  129. _name = "tax.shelter.certificate"
  130. _description = "Tax Shelter Certificate"
  131. _order = "cooperator_number asc"
  132. cooperator_number = fields.Integer(string='Cooperator number',
  133. required=True,
  134. readonly=True)
  135. partner_id = fields.Many2one('res.partner', string='Cooperator',
  136. required=True, readonly=True)
  137. state = fields.Selection([('draft', 'Draft'),
  138. ('validated', 'Validated'),
  139. ('no_eligible', 'No eligible'),
  140. ('sent', 'Sent')],
  141. string='State', required=True, default="draft")
  142. declaration_id = fields.Many2one('tax.shelter.declaration',
  143. string='Declaration', required=True,
  144. readonly=True, ondelete="restrict")
  145. lines = fields.One2many('certificate.line',
  146. 'tax_shelter_certificate',
  147. string='Certificate lines', readonly=True)
  148. previously_subscribed_lines = fields.One2many(compute='_compute_certificate_lines',
  149. comodel_name='certificate.line',
  150. string='Previously Subscribed lines',
  151. readonly=True)
  152. previously_subscribed_eligible_lines = fields.One2many(
  153. compute='_compute_certificate_lines',
  154. comodel_name='certificate.line',
  155. string='Previously Subscribed eligible lines',
  156. readonly=True)
  157. subscribed_lines = fields.One2many(compute='_compute_certificate_lines',
  158. comodel_name='certificate.line',
  159. string='Shares subscribed',
  160. readonly=True)
  161. resold_lines = fields.One2many(compute='_compute_certificate_lines',
  162. comodel_name='certificate.line',
  163. string='Shares resold',
  164. readonly=True)
  165. transfered_lines = fields.One2many(compute='_compute_certificate_lines',
  166. comodel_name='certificate.line',
  167. string='Shares transfered',
  168. readonly=True)
  169. total_amount_previously_subscribed = fields.Float(compute='_compute_amounts',
  170. string='Total previously subscribed')
  171. total_amount_eligible_previously_subscribed = fields.Float(compute='_compute_amounts',
  172. string='Total eligible previously subscribed')
  173. total_amount_subscribed = fields.Float(compute='_compute_amounts',
  174. string='Total subscribed')
  175. total_amount_eligible = fields.Float(compute='_compute_amounts',
  176. string='Total amount eligible To Tax shelter')
  177. total_amount_resold = fields.Float(compute='_compute_amounts',
  178. string='Total resold')
  179. total_amount_transfered = fields.Float(compute='_compute_amounts',
  180. string='Total transfered')
  181. total_amount = fields.Float(compute='_compute_amounts',
  182. string='Total', readonly=True)
  183. company_id = fields.Many2one(related="declaration_id.company_id",
  184. string="Company")
  185. def generate_pdf_report(self, report_type):
  186. report, name = REPORT_DIC[report_type]
  187. report = self.env.ref(report).render_qweb_pdf(self)
  188. report = base64.b64encode(report)
  189. report_name = self.partner_id.name + ' ' + name + ' ' + self.declaration_id.name + '.pdf'
  190. return (report_name, report)
  191. def generate_certificates_report(self):
  192. attachments = []
  193. if self.total_amount_eligible > 0:
  194. attachments.append(self.generate_pdf_report('subscription'))
  195. if self.partner_id.total_value > 0:
  196. attachments.append(self.generate_pdf_report('shares'))
  197. # if self.total_amount_resold > 0 or self.total_amount_transfered > 0:
  198. # TODO
  199. return attachments
  200. @api.multi
  201. def send_certificates(self):
  202. tax_shelter_mail_template = self.env.ref('easy_my_coop_taxshelter_report.email_template_tax_shelter_certificate', False)
  203. for certificate in self:
  204. if certificate.total_amount_eligible + certificate.total_amount_eligible_previously_subscribed > 0:
  205. attachments = certificate.generate_certificates_report()
  206. if len(attachments) > 0:
  207. tax_shelter_mail_template.send_mail_with_multiple_attachments(certificate.id, attachments,True)
  208. certificate.state = 'sent'
  209. else:
  210. certificate.state = 'no_eligible'
  211. self.env.cr.commit()
  212. @api.multi
  213. def print_subscription_certificate(self):
  214. self.ensure_one()
  215. report, name = REPORT_DIC['subscription']
  216. return self.env.ref(report).report_action(self)
  217. @api.multi
  218. def print_shares_certificate(self):
  219. self.ensure_one()
  220. report, name = REPORT_DIC['shares']
  221. return self.env.ref(report).report_action(self)
  222. @api.multi
  223. def _compute_amounts(self):
  224. for certificate in self:
  225. total_amount_previously_subscribed = 0
  226. total_amount_previously_eligible = 0
  227. total_amount_subscribed = 0
  228. total_amount_elligible = 0
  229. total_amount_transfered = 0
  230. total_amount_resold = 0
  231. for line in certificate.subscribed_lines:
  232. total_amount_subscribed += line.amount_subscribed
  233. total_amount_elligible += line.amount_subscribed_eligible
  234. certificate.total_amount_subscribed = total_amount_subscribed
  235. certificate.total_amount_eligible = total_amount_elligible
  236. for line in certificate.previously_subscribed_eligible_lines:
  237. total_amount_previously_eligible += line.amount_subscribed_eligible
  238. certificate.total_amount_eligible_previously_subscribed = total_amount_previously_eligible
  239. for line in certificate.previously_subscribed_lines:
  240. total_amount_previously_subscribed += line.amount_subscribed
  241. certificate.total_amount_previously_subscribed = total_amount_previously_subscribed
  242. for line in certificate.transfered_lines:
  243. total_amount_transfered += line.amount_transfered
  244. certificate.total_amount_transfered = total_amount_transfered
  245. for line in certificate.resold_lines:
  246. total_amount_resold += line.amount_resold
  247. certificate.total_amount_resold = total_amount_resold
  248. certificate.total_amount = certificate.total_amount_previously_subscribed + certificate.total_amount_subscribed + certificate.total_amount_resold + certificate.total_amount_transfered
  249. @api.depends('lines')
  250. def _compute_certificate_lines(self):
  251. for certificate in self:
  252. certificate.previously_subscribed_lines = certificate.lines.filtered(lambda r: r.type == 'subscribed' and r.transaction_date < certificate.declaration_id.date_from)
  253. certificate.previously_subscribed_eligible_lines = certificate.lines.filtered(lambda r: r.type == 'subscribed' and r.transaction_date < certificate.declaration_id.date_from and r.tax_shelter)
  254. certificate.subscribed_lines = certificate.lines.filtered(lambda r: r.type == 'subscribed' and r.transaction_date >= certificate.declaration_id.date_from and r.transaction_date <= certificate.declaration_id.date_to)
  255. certificate.resold_lines = certificate.lines.filtered(lambda r: r.type == 'resold' and r.transaction_date >= certificate.declaration_id.date_from and r.transaction_date <= certificate.declaration_id.date_to)
  256. certificate.transfered_lines = certificate.lines.filtered(lambda r: r.type == 'transfered' and r.transaction_date >= certificate.declaration_id.date_from and r.transaction_date <= certificate.declaration_id.date_to)
  257. @api.model
  258. def batch_send_tax_shelter_certificate(self):
  259. certificates = self.search([('state', '=', 'validated')], limit=80)
  260. certificates.send_certificates()
  261. class TaxShelterCertificateLine(models.Model):
  262. _name = "certificate.line"
  263. _description = "Tax Shelter Certificate Line"
  264. declaration_id = fields.Many2one(related='tax_shelter_certificate.declaration_id',
  265. string="Declaration")
  266. tax_shelter_certificate = fields.Many2one('tax.shelter.certificate',
  267. string="Tax shelter certificate",
  268. ondelete='cascade',
  269. required=True)
  270. share_type = fields.Many2one('product.product',
  271. string='Share type',
  272. required=True,
  273. readonly=True)
  274. share_unit_price = fields.Float(string='Share price',
  275. required=True,
  276. readonly=True)
  277. quantity = fields.Integer(string='Number of shares',
  278. required=True,
  279. readonly=True)
  280. transaction_date = fields.Date(string="Transaction date")
  281. tax_shelter = fields.Boolean(string="Tax shelter eligible", readonly=True)
  282. type = fields.Selection([('subscribed', 'Subscribed'),
  283. ('resold', 'Resold'),
  284. ('transfered', 'Transfered'),
  285. ('kept', 'Kept')],
  286. required=True, readonly=True)
  287. amount_subscribed = fields.Float(compute='_compute_totals',
  288. string='Amount subscribed',
  289. store=True)
  290. amount_subscribed_eligible = fields.Float(compute='_compute_totals',
  291. string='Amount subscribed eligible',
  292. store=True)
  293. amount_resold = fields.Float(compute='_compute_totals',
  294. string='Amount resold',
  295. store=True)
  296. amount_transfered = fields.Float(compute='_compute_totals',
  297. string='Amount transfered',
  298. store=True)
  299. share_short_name = fields.Char(string='Share type name', readonly=True)
  300. capital_before_sub = fields.Float(string="Capital before subscription",
  301. readonly=True)
  302. capital_after_sub = fields.Float(string="Capital after subscription",
  303. readonly=True)
  304. capital_limit = fields.Float(string="Capital limit", readonly=True)
  305. @api.multi
  306. @api.depends('quantity', 'share_unit_price')
  307. def _compute_totals(self):
  308. for line in self:
  309. if line.type == 'subscribed':
  310. line.amount_subscribed = line.share_unit_price * line.quantity
  311. if line.type == 'subscribed' and line.tax_shelter:
  312. if (line.capital_before_sub < line.capital_limit
  313. and line.capital_after_sub >= line.capital_limit):
  314. line.amount_subscribed_eligible = line.capital_limit - line.capital_before_sub #noqa
  315. elif (line.capital_before_sub < line.capital_limit
  316. and line.capital_after_sub <= line.capital_limit):
  317. line.amount_subscribed_eligible = line.share_unit_price * line.quantity #noqa
  318. elif line.capital_before_sub >= line.capital_limit:
  319. line.amount_subscribed_eligible = 0
  320. if line.type == 'resold':
  321. line.amount_resold = line.share_unit_price * -(line.quantity)
  322. if line.type == 'transfered':
  323. line.amount_transfered = line.share_unit_price * -(line.quantity) #noqa