bigdawgbz

import_permit.py

Jul 19th, 2023
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.31 KB | Source Code | 0 0
  1. import io
  2. import qrcode
  3. import base64
  4. import os
  5.  
  6. from PyPDF2 import PdfFileWriter, PdfFileReader
  7. from reportlab.lib.pagesizes import letter
  8. from reportlab.pdfgen import canvas
  9. from odoo import api, fields, models, SUPERUSER_ID, _
  10. from odoo.exceptions import AccessError, UserError, ValidationError
  11. from odoo.tools import float_is_zero, format_amount, format_date, html_keep_url, is_html_empty
  12. from odoo.tools.sql import create_index
  13.  
  14.  
  15. READONLY_FIELD_STATES = {
  16.     state: [('readonly', True)]
  17.     for state in {'review', 'approve', 'reject'}
  18. }
  19.  
  20. LOCKED_FIELD_STATES = {
  21.     state: [('readonly', True)]
  22.     for state in {'approve', 'reject'}
  23. }
  24.  
  25. # INVOICE_STATUS = [
  26. #     ('upselling', 'Upselling Opportunity'),
  27. #     ('invoiced', 'Fully Invoiced'),
  28. #     ('to invoice', 'To Invoice'),
  29. #     ('no', 'Nothing to Invoice')
  30. # ]
  31.  
  32.  
  33. class ImportPermit(models.Model):
  34.     _name = 'import.permit'
  35.     _inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin', 'utm.mixin']
  36.     # _inherit = ['mail.thread', 'mail.activity.mixin']
  37.     _description = "Import Permit Request"
  38.     _order = 'date_order desc, id desc'
  39.     _check_company_auto = True
  40.     _rec_name = 'permit_number'
  41.  
  42.     # _sql_constraints = [
  43.     #     ('date_requested_conditional_required',
  44.     #      "CHECK((state IN ('request', 'approve') AND date_requested IS NOT NULL) OR state NOT IN ('request', 'approved'))",
  45.     #      "A confirmed permit request requires a confirmation date."),
  46.     # ]
  47.  
  48.     @property
  49.     def _rec_names_search(self):
  50.         if self._context.get('permit_show_applicant_name'):
  51.             return ['name', 'applicant_id.name']
  52.         return ['name']
  53.  
  54.     permit_number = fields.Char(
  55.         string="Permit Number",
  56.         required=True,
  57.         copy=False,
  58.         readonly=True,
  59.         index='trigram',
  60.         #states={'draft': [('readonly', False)]},
  61.         state={'draft': [('readonly', False)]},
  62.         default=lambda self: _('New')
  63.     )
  64.  
  65.     company_id = fields.Many2one(
  66.         comodel_name='res.company',
  67.         required=True,
  68.         index=True,
  69.         tracking=True,
  70.         default=lambda self: self.env.company
  71.     )
  72.  
  73.     permit_type = fields.Selection(
  74.         selection=[
  75.             ('Drone', 'Drone'),
  76.             ('General', 'General')
  77.         ],
  78.         # required=True,
  79.         string='Permit Type',
  80.         default='Drone',  # Set the default value to 'Drone'
  81.         tracking=True
  82.     )
  83.  
  84.     state = fields.Selection(
  85.         selection=[
  86.             ('draft', 'Draft'),
  87.             ('submit', 'Submitted'),
  88.             ('review', 'Under Review'),
  89.             ('approve', 'Approved'),
  90.             ('reject', 'Rejected')
  91.         ],
  92.         string="Status",
  93.         readonly=True,
  94.         copy=False,
  95.         index=True,
  96.         tracking=3,
  97.         default='draft'
  98.     )
  99.  
  100.     @api.constrains('fees')
  101.     def _check_fees(self):
  102.         for record in self:
  103.             if record.fees < 0:
  104.                 raise exceptions.ValidationError("Fees must be a positive value.")
  105.  
  106.     @api.model_create_multi
  107.     def create(self, vals_list):
  108.         for vals in vals_list:
  109.             if 'company_id' in vals:
  110.                 self = self.with_company(vals['company_id'])
  111.             if vals.get('permit_number', _("New")) == _("New"):
  112.                 seq_date = fields.Datetime.context_timestamp(
  113.                     self, fields.Datetime.to_datetime(vals['date_request'])
  114.                 ) if 'date_request' in vals else None
  115.                 vals['permit_number'] = self.env['ir.sequence'].next_by_code(
  116.                     'import.permit',
  117.                     sequence_date=seq_date
  118.                 ) or _("New")
  119.  
  120.         return super().create(vals_list)
  121.  
  122.  
  123.     applicant_id = fields.Many2one(
  124.         comodel_name='res.partner',
  125.         string="Customer",
  126.         required=True,
  127.         readonly=False,
  128.         change_default=True,
  129.         index=True,
  130.         tracking=1,
  131.         states=READONLY_FIELD_STATES,
  132.         domain="[('type', '!=', 'private'), ('company_id', 'in', (False, company_id))]"
  133.         # state={'review': [('readonly', True)], 'approve': [('readonly', True)], 'reject': [('readonly', True)]},
  134.         # domain="[('type', '!=', 'private'), ('company_id', 'in', (False, company_id))]"
  135.     )
  136.  
  137.     email = fields.Char(related='applicant_id.email', string="Email", tracking=True)
  138.  
  139.     fees = fields.Float(
  140.         string="Fees",
  141.         default=25.00,
  142.         required=True,
  143.         readonly=False,
  144.         tracking=1,
  145.         state={'review': [('readonly', True)], 'approve': [('readonly', True)], 'reject': [('readonly', True)]}
  146.     )
  147.  
  148.     date_request = fields.Datetime(
  149.         string="Request Date",
  150.         required=True,
  151.         readonly=True,
  152.         index=True,
  153.         default=fields.Datetime.now,
  154.         states=LOCKED_FIELD_STATES,
  155.         copy=False
  156.     )
  157.  
  158.     paid_date = fields.Date(
  159.         string="Paid Date",
  160.         copy=False,
  161.         readonly=True,
  162.         state={'draft': [('readonly', False)]},
  163.         index=True,
  164.         default=fields.Date.context_today,
  165.         tracking=2
  166.     )
  167.     attachment_ids = fields.Many2many(
  168.         comodel_name='ir.attachment',
  169.         relation='import_permit_attachment_rel',
  170.         column1='import_permit_id',
  171.         column2='attachment_id',
  172.         string="Attachments",
  173.         states=LOCKED_FIELD_STATES,
  174.         help="Related Attachments"
  175.     )
  176.  
  177.     certificate = fields.Binary(
  178.         string="Certificate",
  179.         readonly=True,
  180.         state={'approve': [('readonly', False)]},
  181.         attachment=True
  182.     )
  183.  
  184.     certificate_filename = fields.Char(
  185.         string="Certificate Filename",
  186.         readonly=True,
  187.         state={'approve': [('readonly', False)]}
  188.     )
  189.  
  190.     mobile = fields.Char(related='applicant_id.mobile', string="Mobile", tracking=True)
  191.     street = fields.Char(related='applicant_id.street', string="Address", tracking=True)
  192.     street2 = fields.Char(related='applicant_id.street2', string="Address", tracking=True)
  193.     city = fields.Char(related='applicant_id.city', string="Address", tracking=True)
  194.     state_id = fields.Many2one(related='applicant_id.state_id', string="Address", tracking=True)
  195.     zip = fields.Char(related='applicant_id.zip', string="Address", tracking=True)
  196.     country_id = fields.Many2one(related='applicant_id.country_id', string="Address", tracking=True)
  197.     birth_date = fields.Date(string='Birth Date', tracking=True)
  198.     id_type = fields.Selection(
  199.         [
  200.             ('passport', 'Passport'),
  201.             ('social', 'Social Security'),
  202.             ('drivers', 'Drivers License')
  203.         ],
  204.         string="Identification Type",
  205.         tracking=True
  206.     )
  207.     create_date = fields.Datetime(  # Override of default create_date field from ORM
  208.         string="Creation Date", index=True, readonly=True)
  209.     date_requested = fields.Datetime(
  210.         string="Requested Date",
  211.         required=True, readonly=False, copy=False,
  212.         states=READONLY_FIELD_STATES,
  213.         help="Creation date of draft/sent permits,\nConfirmation date of confirmed requests.",
  214.         default=fields.Datetime.now)
  215.     id_number = fields.Char(string="Identification Number", tracking=True)
  216.     permit_printed_by = fields.Many2one('res.users', readonly=True)
  217.     permit_printed_on = fields.Datetime(readonly=True)
  218.     requested_date = fields.Date(string="Requested Date", default=fields.Date.context_today)
  219.     bank_account_info = fields.Many2one('res.partner.bank', string='Company Bank Account Information')
  220.     approved_by = fields.Many2one('res.users', string='Approved By', default=lambda self: self.env.user, readonly=True)
  221.     approved_date = fields.Datetime(string='Approved Date', readonly=True)
  222.     approval_signature = fields.Binary(string="Signature", attachment=True, state={'approve': [('readonly', False)]})
  223.     notes = fields.Text(string="Additional Notes", tracking=True)
  224.     receipt = fields.Many2many('ir.attachment', string="Receipt", tracking=True)
  225.     receipt_no = fields.Char(tracking=True)
  226.     drone_permit_ids = fields.One2many(
  227.         comodel_name='import.permit.drone',
  228.         inverse_name='import_permit_id',
  229.         string='Drone Permits'
  230.     )
  231.     general_permit_ids = fields.One2many(
  232.         comodel_name='import.permit.general',
  233.         inverse_name='import_permit_id',
  234.         string='General Permits'
  235.     )
  236.  
  237.     @api.depends('state')
  238.     def _compute_is_locked(self):
  239.         for record in self:
  240.             record.is_locked = record.state in {'approve', 'reject'}
  241.  
  242.     is_locked = fields.Boolean(
  243.         compute='_compute_is_locked',
  244.         store=True,
  245.         string='Is Locked',
  246.         help="If True, the import permit is locked and cannot be edited."
  247.     )
  248.  
  249.     def _prepare_certificate_values(self):
  250.         self.ensure_one()
  251.  
  252.         if self.permit_type == 'Drone':
  253.             permit_type_label = _("Drone Import Permit")
  254.         else:
  255.             permit_type_label = _("General Import Permit")
  256.  
  257.         certificate_values = {
  258.             'name': permit_type_label,
  259.             'permit_number': self.permit_number,
  260.             'applicant_name': self.applicant_id.name,
  261.             'fees': self.fees,
  262.         }
  263.  
  264.         return certificate_values
  265.     def _generate_certificate_pdf(self, certificate_values):
  266.         self.ensure_one()
  267.  
  268.         # Create a new PDF document
  269.         buffer = io.BytesIO()
  270.         c = canvas.Canvas(buffer, pagesize=letter)
  271.  
  272.         # Set the font and font size
  273.         c.setFont('Helvetica', 12)
  274.  
  275.         # Write the certificate details
  276.         c.drawString(100, 700, certificate_values['name'])
  277.         c.drawString(100, 670, _("Permit Number: {}".format(certificate_values['permit_number'])))
  278.         c.drawString(100, 640, _("Applicant Name: {}".format(certificate_values['applicant_name'])))
  279.  
  280.         c.showPage()
  281.         c.save()
  282.  
  283.         # Get the PDF buffer value
  284.         pdf_buffer = buffer.getvalue()
  285.         buffer.close()
  286.  
  287.         return pdf_buffer
  288.  
  289.     def _generate_certificate_qrcode(self, certificate_values):
  290.         self.ensure_one()
  291.  
  292.         # Generate the QR code data
  293.         qr_code_data = {
  294.             'Permit Number': certificate_values['permit_number'],
  295.             'Applicant Name': certificate_values['applicant_name'],
  296.             'Fees': str(certificate_values['fees']),
  297.         }
  298.  
  299.         qr_code_string = str(qr_code_data)
  300.  
  301.         # Generate the QR code image
  302.         qr_code_img = qrcode.make(qr_code_string)
  303.  
  304.         # Convert the image to a byte stream
  305.         qr_code_byte_stream = io.BytesIO()
  306.         qr_code_img.save(qr_code_byte_stream, format='PNG')
  307.         qr_code_byte_stream.seek(0)
  308.  
  309.         # Get the base64 encoded value of the image byte stream
  310.         qr_code_base64 = base64.b64encode(qr_code_byte_stream.getvalue()).decode('utf-8')
  311.  
  312.         return qr_code_base64
  313.  
  314.     def _send_certificate_email(self, certificate_pdf, email):
  315.         self.ensure_one()
  316.  
  317.         # Create a temporary directory to store the PDF file
  318.         temp_dir = '/tmp/certificate'
  319.         os.makedirs(temp_dir, exist_ok=True)
  320.  
  321.         # Save the PDF file in the temporary directory
  322.         certificate_path = os.path.join(temp_dir, 'certificate.pdf')
  323.         with open(certificate_path, 'wb') as f:
  324.             f.write(certificate_pdf)
  325.  
  326.         # Compose the email
  327.         subject = _("Import Permit Certificate")
  328.         body = _("Please find attached the import permit certificate.")
  329.  
  330.         # Attach the PDF file to the email
  331.         attachments = [(os.path.basename(certificate_path), open(certificate_path, 'rb').read())]
  332.  
  333.         # Send the email
  334.         self.env['mail.mail'].create({
  335.             'subject': subject,
  336.             'email_to': email,
  337.             'body': body,
  338.             'attachment_ids': attachments
  339.         }).send()
  340.  
  341.     def action_approve(self):
  342.         for permit in self:
  343.             certificate_values = permit._prepare_certificate_values()
  344.             certificate_pdf = permit._generate_certificate_pdf(certificate_values)
  345.             permit.certificate = base64.b64encode(certificate_pdf)
  346.             permit.certificate_filename = 'import_permit_certificate.pdf'
  347.             permit.state = 'approve'
  348.  
  349.             # Send the certificate by email
  350.             permit._send_certificate_email(certificate_pdf, permit.email)
  351.  
  352.         return True
  353.  
  354.     def action_reject(self):
  355.         self.state = 'reject'
  356.  
  357.     def action_reset_draft(self):
  358.         self.state = 'draft'
  359.  
  360.     def action_draft(self):
  361.         self.write({'state': 'draft'})
  362.  
  363.     def action_submit(self):
  364.         qr_data = {
  365.             'applicant_id': self.applicant_id.name,
  366.             'mobile': self.applicant_id.mobile,
  367.             'permit_number': self.permit_number,
  368.             'fees': self.fees,
  369.             'bank_account_info': self.bank_account_info.name if self.bank_account_info else None,
  370.         }
  371.         qr_img = qrcode.make(str(qr_data))
  372.  
  373.         img_buffer = io.BytesIO()
  374.         qr_img.save(img_buffer, format='PNG')
  375.         img_buffer.seek(0)
  376.         img_data = base64.b64encode(img_buffer.read())
  377.  
  378.         self.write({'state': 'submit'})
  379.  
  380.     def action_review(self):
  381.         self.write({'state': 'review'})
  382.  
  383.  
  384. class ImportPermitDrone(models.Model):
  385.     _name = 'import.permit.drone'
  386.     _description = 'Drone Import Permit'
  387.  
  388.     import_permit_id = fields.Many2one(
  389.         comodel_name='import.permit',
  390.         string='Import Permit',
  391.         #required=True,
  392.         ondelete='cascade',
  393.         index=True
  394.     )
  395.  
  396.     drone_type = fields.Char(string='Drone Type', tracking=True)
  397.     drone_make = fields.Char(string='Make', tracking=True)
  398.     drone_model = fields.Char(string='Model', tracking=True)
  399.     drone_color = fields.Char(string='Color', tracking=True)
  400.     num_engines = fields.Integer(string='Number of Engines', tracking=True)
  401.     drone_serial_number = fields.Char(string='Serial Number', tracking=True)
  402.     drone_quantity = fields.Integer(string="Quantity", tracking=True)
  403.     documents = fields.Binary(string="Documents", tracking=True)
  404.     documents_filename = fields.Char(string="Documents Filename")
  405.     drone_stay_in_belize = fields.Selection(
  406.         [('yes', 'Yes'), ('no', 'No')],
  407.         string='Drone Stay in Belize',
  408.         default='yes',
  409.         tracking=True,
  410.         state={'Draft': [('invisible', True)]}
  411.     )
  412.     departure_date = fields.Date(
  413.         string='Departure Date',
  414.         tracking=True,
  415.         state={'Draft': [('required', True)]},
  416.         help="The date when the drone is leaving Belize",
  417.         attrs={'invisible': [('drone_stay_in_belize', '=', 'yes')]}
  418.     )
  419.  
  420.     @api.onchange('documents')
  421.     def _onchange_documents(self):
  422.         if self.documents:
  423.             self.documents_filename = "Documents"
  424.  
  425.     def open_document(self):
  426.         self.ensure_one()
  427.         return {
  428.             'type': 'ir.actions.act_url',
  429.             'url': f'/web/content/{self._name}/{self.id}/documents',
  430.             'target': 'self',
  431.         }
  432.  
  433.     def _get_default_import_permit(self):
  434.         # Get the default import permit based on your logic (e.g., current user, date, etc.)
  435.         default_import_permit = self.env['import.permit'].search([...], limit=1)
  436.         return default_import_permit.id
  437.  
  438.  
  439. class ImportPermitGeneral(models.Model):
  440.     _name = 'import.permit.general'
  441.     _description = 'General Import Permit'
  442.  
  443.     import_permit_id = fields.Many2one(
  444.         comodel_name='import.permit',
  445.         string='Import Permit',
  446.         required=True,
  447.         ondelete='cascade',
  448.         index=True
  449.     )
  450.  
  451.     imported_goods_type = fields.Char(string='Type', tracking=True)
  452.     imported_goods_make = fields.Char(string='Make', tracking=True)
  453.     imported_goods_model = fields.Char(string='Model', tracking=True)
  454.     imported_goods_quantity = fields.Integer(string='Quantity', tracking=True)
  455.     imported_goods_serial_number = fields.Char(string='Serial Number', tracking=True)
  456.     documents = fields.Binary(string="Documents", tracking=True)
  457.     documents_filename = fields.Char(string="Documents Filename")
  458.  
  459.     @api.onchange('documents')
  460.     def _onchange_documents(self):
  461.         if self.documents:
  462.             self.documents_filename = "Documents"
  463.  
  464.     def open_document(self):
  465.         self.ensure_one()
  466.         return {
  467.             'type': 'ir.actions.act_url',
  468.             'url': f'/web/content/{self._name}/{self.id}/documents',
  469.             'target': 'self',
  470.         }
  471.  
Tags: Odoo
Add Comment
Please, Sign In to add comment