Advertisement
Kenjx

Sales Contracts

Apr 30th, 2024
813
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 18.12 KB | None | 0 0
  1. class SaleContracts(models.Model):
  2.     _name = "sales.contracts"
  3.     _inherit = ["mail.thread", "mail.activity.mixin", "utm.mixin"]
  4.     _order = "id desc"
  5.  
  6.     @api.depends("payments")
  7.     def get_payments_total(self):
  8.         """Calculate total payments."""
  9.         for rec in self:
  10.             rec.payments_total = sum(line.amount for line in rec.payments)
  11.  
  12.     @api.depends("payments", "amount")
  13.     def get_balance_total(self):
  14.         """Calculate total balance."""
  15.         for rec in self:
  16.             rec.balance_total = rec.amount - rec.payments_total
  17.  
  18.             # Check status of the contract
  19.             rec._check_contract_status()
  20.  
  21.     name = fields.Char(
  22.         string="Contract No.", readonly=True, required=True, copy=False, default="New"
  23.     )
  24.     chassis_no = fields.Char("Chassis No")
  25.  
  26.     def create_im4_bill(self):
  27.         """Create IM4 Bill."""
  28.         for item in self:
  29.             if not item.im4:
  30.                 continue
  31.  
  32.             return {
  33.                 "view_id": self.env.ref("carbiz_client.vehicle_im7_clearance_form1").id,
  34.                 "view_mode": "form",
  35.                 "res_model": "carbiz.t1",
  36.                 "res_id": item.im4.id,
  37.                 "type": "ir.actions.act_window",
  38.                 "target": "new",
  39.                 "context": self._context,
  40.             }
  41.  
  42.     def add_im4(self):
  43.         for item in self:
  44.             # Skip if IM4 already exists
  45.             if item.im4:
  46.                 _logger.info("IM4 already exists, checking its state...")
  47.                 if item.state_im4 == "draft":
  48.                     _logger.info("IM4 is in draft state...")
  49.                     context = dict(self._context or {})
  50.                     return {
  51.                         # 'view_type': 'form',
  52.                         "view_id": self.env.ref(
  53.                             "carbiz_client.vehicle_im4_clearance_form1"
  54.                         ).id,
  55.                         "view_mode": "form",
  56.                         "res_model": "carbiz.t1",
  57.                         "res_id": item.im4.id,
  58.                         "type": "ir.actions.act_window",
  59.                         "target": "new",
  60.                         "context": context,
  61.                     }
  62.                 continue
  63.  
  64.             # Search for car_id
  65.             car_id = self.env["carbiz_erp.vehicle"].search(
  66.                 [("product", "=", item.product_id.id)], limit=1
  67.             )
  68.  
  69.             # Check for existing IM4
  70.             existing_im4 = self.env["carbiz.t1"].search(
  71.                 [("car_id", "=", car_id.id), ("state_im7", "=", "im4")], limit=1
  72.             )
  73.             if existing_im4:
  74.                 item.im4 = existing_im4.id
  75.                 item.im4.add_im4()
  76.                 continue
  77.  
  78.             # If there's no existing IM4, check for IM7
  79.             existing_im7 = self.env["carbiz.t1"].search(
  80.                 [
  81.                     ("car_id", "=", car_id.id),
  82.                     ("state_im7", "not in", ("expired", "im4", "cancel")),
  83.                 ],
  84.                 limit=1,
  85.             )
  86.             if existing_im7:
  87.                 item.im4 = existing_im7.id
  88.                 return existing_im7.add_im4()
  89.  
  90.             # If there's no IM7 or IM4 record for this vehicle, raise an error
  91.             raise UserError(
  92.                 _("There's no IM7 or IM4 record for this vehicle!\n Something is wrong!")
  93.             )
  94.  
  95.     im4 = fields.Many2one("carbiz.t1", string="IM4")
  96.     im4_bill = fields.Many2one(
  97.         "account.move", string="IM4 Bill", related="im4.im4_bill", store=True
  98.     )
  99.     im4_bill_state = fields.Selection(
  100.         related="im4_bill.payment_state", store=True, string="IM4 Bill State"
  101.     )
  102.  
  103.     state_im4 = fields.Selection(
  104.         [
  105.             ("draft", "Draft"),
  106.             ("confirm", "Validated"),
  107.             ("cancel", "Canceled"),
  108.         ],
  109.         string="IM4 Status",
  110.         related="im4.state_im4",
  111.         store=True,
  112.     )
  113.  
  114.     model = fields.Many2one("fleet.vehicle.model", "Model")
  115.     product_id = fields.Many2one("product.product", "Vehicle")
  116.     reg_no = fields.Many2one("fleet.vehicle", "Reg No")
  117.     sales_person = fields.Many2one("res.users", "Salesperson")
  118.     reg_type = fields.Selection(
  119.         [
  120.             ("localuse", "Local Use"),
  121.             ("reexport", "Re-export"),
  122.             ("taxfree", "Tax Free"),
  123.         ],
  124.         default="localuse",
  125.         string="Registration Type",
  126.     )
  127.     color = fields.Char("Colour")
  128.     file_no = fields.Char("Origin")
  129.  
  130.     customer = fields.Many2one("res.partner", string="Purchaser")
  131.     address = fields.Char("City")
  132.     phone = fields.Char("Phone", related="customer.phone")
  133.     po_box = fields.Char("Street", related="customer.street")
  134.     country_id = fields.Many2one("res.country", string="Country")
  135.     sales_order = fields.Many2one("sale.order", string="Origin")
  136.     delivery_count = fields.Integer(related="sales_order.delivery_count", store=True)
  137.     invoice_count = fields.Integer(related="sales_order.invoice_count", store=True)
  138.     start_date =  fields.Date("Installment Start Date", default=fields.Date.today())
  139.  
  140.     def action_view_delivery(self):
  141.         return self.sales_order.action_view_delivery()
  142.  
  143.     def action_view_invoice(self):
  144.         return self.sales_order.action_view_invoice()
  145.  
  146.     @api.depends("customer_bills")
  147.     def _compute_customer_bills_count(self):
  148.         """Compute customer bills count."""
  149.         account_move = self.env["account.move"]
  150.         for record in self:
  151.             record.bills_count = account_move.search_count(
  152.                 [("contract_id", "=", record.id), ("move_type", "=", "out_invoice")]
  153.             )
  154.  
  155.     @api.depends("payments")
  156.     def _compute_customer_payments_count(self):
  157.         """Compute customer payments count."""
  158.         account_payment = self.env["account.payment"]
  159.         for record in self:
  160.             record.payments_count = account_payment.search_count(
  161.                 [("contract_id", "=", record.id)]
  162.             )
  163.  
  164.             record._compute_delivery_request()
  165.  
  166.     @api.depends("down_payment")
  167.     def _compute_delivery_request(self):
  168.         for rec in self:
  169.             # Balance Before Delivery sum
  170.             beforedelivery_payment_amounts = sum(
  171.                 line.amount
  172.                 for line in rec.payments.filtered(
  173.                     lambda pay: pay.carbiz_payment_type == "balbeforedelivery"
  174.                 )
  175.             )
  176.        
  177.             # Down Payments
  178.             down_payment_amounts = sum(
  179.                 line.amount
  180.                 for line in rec.payments.filtered(
  181.                     lambda pay: pay.carbiz_payment_type == "downpayment"
  182.                 )
  183.             )
  184.             rec.make_delivery = False
  185.            
  186.             # Check if the total amount lets to cause delivery
  187.             if down_payment_amounts == rec.down_payment and  (rec.balance > 0 and beforedelivery_payment_amounts == rec.balance):
  188.                 rec.make_delivery = True            
  189.             elif down_payment_amounts == rec.down_payment and not rec.balance:
  190.                 rec.make_delivery = True
  191.                
  192.                
  193.  
  194.             # Check the car status, if in bond or not
  195.             picking = rec.product_id.stock_move_ids.filtered(
  196.                 lambda car: car.product_id == rec.product_id
  197.                 and car.state == "done"
  198.                 and car.picking_code == "outgoing"
  199.             )
  200.  
  201.             if not len(picking) == 0:
  202.                 rec.make_delivery = False
  203.  
  204.     product_id = fields.Many2one("product.product", string="Product")
  205.     amount = fields.Float("Amount in Figures")
  206.     payments_total = fields.Float("Amount Paid", compute=get_payments_total, store=True)
  207.     balance_total = fields.Float(
  208.         "Total Amount Outstanding", compute=get_balance_total, store=True
  209.     )
  210.     amount_words = fields.Char("Amount in Words", tracking=True)
  211.     down_payment = fields.Float("Down Payment")
  212.     balance = fields.Float("Amount Before Delivery")
  213.     days_balance = fields.Integer("Days to clear balance")
  214.     balance_installment = fields.Float("Installment Balance")
  215.     days_installment = fields.Integer("Days to clear installments")
  216.     days = fields.Integer("Days to clear installment")
  217.     date_delivery = fields.Date("Final Day Delivery")
  218.     date_installment = fields.Date("Final Day Installment")
  219.     no_install = fields.Integer("No. of Installments")
  220.     installment_lines = fields.One2many(
  221.         "install.line", "contract_id", string="Installments"
  222.     )
  223.     customer_bills = fields.One2many(
  224.         "account.move", "contract_id", string="Customer Bills"
  225.     )
  226.     payment_lines = fields.One2many(
  227.         "contract.payment", "contract_id", string="Payments"
  228.     )
  229.     payments = fields.One2many(
  230.         "account.payment",
  231.         "contract_id",
  232.         string="Payments",
  233.         domain=[("state", "=", "posted")],
  234.     )
  235.     payments_count = fields.Integer(compute="_compute_customer_payments_count")
  236.     # bills_count = fields.Integer(compute="_compute_customer_bills_count")
  237.     make_delivery = fields.Boolean(
  238.         default=False, compute="_compute_delivery_request", store=True
  239.     )
  240.     assigned = fields.Boolean(default=False)
  241.     is_other_existing_contract = fields.Boolean(default=False)
  242.  
  243.     state = fields.Selection(
  244.         [
  245.             ("draft", "Draft"),
  246.             ("running", "Running"),
  247.             ("completed", "Completed"),
  248.             ("cancelled", "Cancelled"),
  249.         ],
  250.         default="draft",
  251.         string="State",
  252.     )
  253.  
  254.     def create_delivery(self):
  255.         """Create a delivery on demand"""
  256.         for rec in self.sales_order.order_line:
  257.             if rec.product_id == self.product_id:
  258.                 rec._action_launch_stock_rule()
  259.                 self.make_delivery = False
  260.  
  261.     @api.depends("balance_total")
  262.     def _check_contract_status(self):
  263.         for rec in self:
  264.             if (
  265.                 rec.balance_total == 0
  266.                 and rec.payments_total == rec.amount
  267.                 and rec.state == "running"
  268.             ):
  269.                 rec.state = "completed"
  270.  
  271.     # def create_customer_bills(self):
  272.     #     for contract in self:
  273.     #         invoice_line_vals = []
  274.     #         invoice_line_vals.append((0, 0, {
  275.     #             'product_id': contract.product_id.id,
  276.     #             'price_unit': contract.amount,
  277.     #             'tax_ids': False,
  278.     #             # 'currency_id' : contract.billing_currency,
  279.     #             'quantity': 1,
  280.     #         }))
  281.  
  282.     #         invoice_vals = {
  283.     #             'partner_id': contract.customer.id,
  284.     #             'move_type': 'out_invoice',
  285.     #             'invoice_date': date.today(),
  286.     #             "contract_id": contract.id,
  287.     #             'invoice_line_ids': invoice_line_vals
  288.     #         }
  289.  
  290.     #         customer_bills = self.env['account.move'].create(invoice_vals)
  291.  
  292.     def show_bills(self):
  293.         return {
  294.             "name": "Contracts",
  295.             "domain": [
  296.                 ("contract_id", "=", self.id),
  297.                 ("move_type", "=", "out_invoice"),
  298.             ],
  299.             "view_type": "form",
  300.             "res_model": "account.move",
  301.             "view_id": False,
  302.             "view_mode": "tree,form",
  303.             "type": "ir.actions.act_window",
  304.             "context": "{'create': False}",
  305.         }
  306.  
  307.     def show_payments(self):
  308.         return {
  309.             "name": "Payments",
  310.             "domain": [("contract_id", "=", self.id)],
  311.             "view_type": "tree,form",
  312.             "res_model": "account.payment",
  313.             "view_id": False,
  314.             "view_mode": "tree,form",
  315.             "type": "ir.actions.act_window",
  316.             "context": "{'create': False}",
  317.         }
  318.  
  319.     def show_deliveries(self):
  320.         return {
  321.             "name": "Job Cards",
  322.             "domain": [("contract_id", "=", self.id)],
  323.             "view_type": "form",
  324.             "res_model": "rtt.jobcard",
  325.             "view_id": False,
  326.             "view_mode": "tree,form",
  327.             "type": "ir.actions.act_window",
  328.             "context": "{'create': False}",
  329.         }
  330.  
  331.     @api.model
  332.     def create(self, vals):
  333.         if vals.get("name", "New") == "New":
  334.             vals["name"] = (
  335.                 self.env["ir.sequence"].next_by_code("contract.sequence") or "New"
  336.             )
  337.         return super().create(vals)
  338.  
  339.     def receive_payment(self):
  340.         pay_journals = self.env["account.journal"].search(
  341.             [("type", "in", ("bank", "cash"))], limit=1
  342.         )
  343.         for rec in self:
  344.             context = dict(
  345.                 {
  346.                     "default_payment_type": "inbound",
  347.                     "default_partner_type": "customer",
  348.                     "default_ref": rec.name,
  349.                     "default_date": date.today(),
  350.                     "default_destination_account_id": rec.customer.property_account_receivable_id.id,
  351.                     "default_journal_id": pay_journals.id,
  352.                     "default_partner_id": rec.customer.id,
  353.                     "default_currency_id": rec.sales_order.currency_id.id,
  354.                     "default_carbiz_contract_payment": True,
  355.                     "default_contract_id": rec.id,
  356.                 }
  357.             )
  358.  
  359.             return {
  360.                 "name": _("Collect Payment"),
  361.                 "view_id": self.env.ref("account.view_account_payment_form").id,
  362.                 "view_mode": "form",
  363.                 "res_model": "account.payment",
  364.                 "type": "ir.actions.act_window",
  365.                 "target": "new",
  366.                 "context": context,
  367.             }
  368.  
  369.     @api.onchange("days_balance", "days_installment")
  370.     def update_dates(self):
  371.         for rec in self:
  372.             if rec.days_balance > 0:
  373.                 rec.date_delivery = date.today() + relativedelta(days=rec.days_balance)
  374.             if rec.days_balance == 0:
  375.                 rec.date_delivery = date.today()
  376.             if rec.days_installment:
  377.                 rec.date_installment = date.today() + relativedelta(
  378.                     days=rec.days_installment
  379.                 )
  380.  
  381.     def start_contract(self):
  382.         # fields_to_check = ['down_payment', 'days_installment', 'no_install', 'days_balance', 'balance']
  383.         fields_to_check = ["balance", "days_balance"]
  384.  
  385.         for rec in self:
  386.             # Car check in by contracts
  387.             car_search_by_contract_ids = self.search(
  388.                 [
  389.                     ("product_id", "=", rec.product_id.id),
  390.                     ("id", "!=", self.id),
  391.                     ("state", "=", "running")
  392.                 ]
  393.             )
  394.  
  395.             if len(car_search_by_contract_ids) > 0:
  396.                 rec.is_other_existing_contract = True
  397.  
  398.             # Add chassis number
  399.             # Search for car_id
  400.             car_id = self.env["carbiz_erp.vehicle"].search(
  401.                 [("product", "=", rec.product_id.id)], limit=1
  402.             )
  403.  
  404.             rec.chassis_no = car_id.name
  405.  
  406.             # For not-straightforward payment
  407.             if not (rec.amount == rec.down_payment) and rec.balance_installment < 1:
  408.                 for field in fields_to_check:
  409.                     if getattr(rec, field) < 1:
  410.                         raise UserError(
  411.                             _(
  412.                                 "Provide the {} amount.".format(
  413.                                     field.replace("_", " ").capitalize()
  414.                                 )
  415.                             )
  416.                         )
  417.  
  418.             rec.state = "running"
  419.             if rec.balance_installment > 0:
  420.                 rec.compute_installments()
  421.             rec._check_contract_status()  # Check if the contract is already fulfilled
  422.  
  423.     def cancel_contract(self):
  424.         for rec in self:
  425.             if rec.is_other_existing_contract:
  426.                 rec.is_other_existing_contract = False
  427.  
  428.             rec.state = "cancelled"
  429.  
  430.     def reset_contract(self):
  431.         for rec in self:
  432.             rec.state = "draft"
  433.  
  434.             # Clear payments information
  435.             for payment in rec.payments:
  436.                 payment.action_draft()
  437.                 payment.action_cancel()
  438.             rec.payments = [(6, 0, 0)]
  439.  
  440.     def auto_complete_contract(self):
  441.         for rec in self:
  442.             contract_records = self.env["sales.contracts"].search([])
  443.             for data in contract_records:
  444.                 if data.state == "running":
  445.                     data.state = "completed"
  446.  
  447.     @api.onchange("amount", "down_payment", "balance")
  448.     def calc_balance(self):
  449.         for rec in self:
  450.             # if rec.down_payment != 0.0:
  451.             rec.balance_installment = rec.amount - (rec.down_payment + rec.balance)
  452.  
  453.     def compute_installments(self):
  454.         fields_to_check = ["days_installment", "no_install"]
  455.  
  456.         for rec in self:
  457.             if not rec.start_date:
  458.                 raise UserError("Please state the installment start date.")
  459.            
  460.             # Validate first fields
  461.             for field in fields_to_check:
  462.                 if getattr(rec, field) < 1:
  463.                     raise UserError(
  464.                         _(
  465.                             "Provide the {} amount.".format(
  466.                                 field.replace("_", " ").capitalize()
  467.                             )
  468.                         )
  469.                     )
  470.  
  471.             rec.installment_lines.unlink()
  472.  
  473.             interval = int(rec.days_installment / rec.no_install)
  474.             amounts = rec.balance_installment / rec.no_install
  475.             due_dates = [
  476.                  rec.start_date + relativedelta(days=i * interval)
  477.                 for i in range(1, rec.no_install + 1)
  478.             ]
  479.  
  480.             for due_date in due_dates:
  481.                 self.env["install.line"].create(
  482.                     {
  483.                         "name": rec.product_id.name + "-" + str(due_date),
  484.                         "amount": amounts,
  485.                         "balance": amounts,
  486.                         "due_date": due_date,
  487.                         "status": "pending",
  488.                         "amount_paid": 0.0,
  489.                         "contract_id": rec.id,
  490.                     }
  491.                 )
  492.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement