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.
		
		
		
		
		
			
		
			
				
					
					
						
							503 lines
						
					
					
						
							22 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							503 lines
						
					
					
						
							22 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ################################################################################### | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2022-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). | |
| #    Author: Megha K (<https://www.cybrosys.com>) | |
| # | |
| #    This program is free software: you can modify | |
| #    it under the terms of the GNU Affero General Public License (AGPL) as | |
| #    published by the Free Software Foundation, either version 3 of the | |
| #    License, or (at your option) any later version. | |
| # | |
| #    This program is distributed in the hope that it will be useful, | |
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| #    GNU Affero General Public License for more details. | |
| # | |
| #    You should have received a copy of the GNU Affero General Public License | |
| #    along with this program.  If not, see <https://www.gnu.org/licenses/>. | |
| # | |
| ################################################################################### | |
| 
 | |
| from werkzeug import urls | |
| from odoo import api, fields, models, _ | |
| from odoo.exceptions import ValidationError | |
| 
 | |
| 
 | |
| class FreightOrder(models.Model): | |
|     _name = 'freight.order' | |
|     _description = 'Freight Order' | |
| 
 | |
|     name = fields.Char('Name', default='New', readonly=True) | |
|     shipper_id = fields.Many2one('res.partner', 'Shipper', required=True, | |
|                                  help="Shipper's Details") | |
|     consignee_id = fields.Many2one('res.partner', 'Consignee', | |
|                                    help="Details of consignee") | |
|     type = fields.Selection([('import', 'Import'), ('export', 'Export')], | |
|                             'Import/Export', required=True, | |
|                             help="Type of freight operation") | |
|     transport_type = fields.Selection([('land', 'Land'), ('air', 'Air'), | |
|                                        ('water', 'Water')], "Transport", | |
|                                       help='Type of transportation', | |
|                                       required=True) | |
|     land_type = fields.Selection([('ltl', 'LTL'), ('ftl', 'FTL')], | |
|                                  'Land Shipping', | |
|                                  help="Types of shipment movement involved in Land") | |
|     water_type = fields.Selection([('fcl', 'FCL'), ('lcl', 'LCL')], | |
|                                   'Water Shipping', | |
|                                   help="Types of shipment movement involved in Water") | |
|     order_date = fields.Date('Date', default=fields.Date.today(), | |
|                              help="Date of order") | |
|     loading_port_id = fields.Many2one('freight.port', string="Loading Port", | |
|                                       required=True, | |
|                                       help="Loading port of the freight order") | |
|     discharging_port_id = fields.Many2one('freight.port', | |
|                                           string="Discharging Port", | |
|                                           required=True, | |
|                                           help="Discharging port of freight order") | |
|     state = fields.Selection([('draft', 'Draft'), ('submit', 'Submitted'), | |
|                               ('confirm', 'Confirmed'), | |
|                               ('invoice', 'Invoiced'), ('done', 'Done'), | |
|                               ('cancel', 'Cancel')], default='draft') | |
|     clearance = fields.Boolean("Clearance") | |
|     clearance_count = fields.Integer(compute='compute_count') | |
|     invoice_count = fields.Integer(compute='compute_count') | |
|     total_order_price = fields.Float('Total', | |
|                                      compute='_compute_total_order_price') | |
|     total_volume = fields.Float('Total Volume', | |
|                                 compute='_compute_total_order_price') | |
|     total_weight = fields.Float('Total Weight', | |
|                                 compute='_compute_total_order_price') | |
|     order_ids = fields.One2many('freight.order.line', 'order_id') | |
|     route_ids = fields.One2many('freight.order.routes.line', 'route_id') | |
|     total_route_sale = fields.Float('Total Sale', | |
|                                     compute="_compute_total_route_cost") | |
|     service_ids = fields.One2many('freight.order.service', 'line_id') | |
|     total_service_sale = fields.Float('Service Total Sale', | |
|                                       compute="_compute_total_service_cost") | |
|     agent_id = fields.Many2one('res.partner', 'Agent', required=True, | |
|                                help="Details of agent") | |
|     expected_date = fields.Date('Expected Date') | |
|     track_ids = fields.One2many('freight.track', 'track_id') | |
| 
 | |
|     @api.depends('order_ids.total_price', 'order_ids.volume', | |
|                  'order_ids.weight') | |
|     def _compute_total_order_price(self): | |
|         """Computing the price of the order""" | |
|         for rec in self: | |
|             rec.total_order_price = sum(rec.order_ids.mapped('total_price')) | |
|             rec.total_volume = sum(rec.order_ids.mapped('volume')) | |
|             rec.total_weight = sum(rec.order_ids.mapped('weight')) | |
| 
 | |
|     @api.depends('route_ids.sale') | |
|     def _compute_total_route_cost(self): | |
|         """Computing the total cost of route operation""" | |
|         for rec in self: | |
|             rec.total_route_sale = sum(rec.route_ids.mapped('sale')) | |
| 
 | |
|     @api.depends('service_ids.total_sale') | |
|     def _compute_total_service_cost(self): | |
|         """Computing the total cost of services""" | |
|         for rec in self: | |
|             rec.total_service_sale = sum(rec.service_ids.mapped('total_sale')) | |
| 
 | |
|     @api.model | |
|     def create(self, vals): | |
|         """Create Sequence""" | |
|         sequence_code = 'freight.order.sequence' | |
|         vals['name'] = self.env['ir.sequence'].next_by_code(sequence_code) | |
|         return super(FreightOrder, self).create(vals) | |
| 
 | |
|     def create_custom_clearance(self): | |
|         """Create custom clearance""" | |
|         clearance = self.env['custom.clearance'].create({ | |
|             'name': 'CC - ' + self.name, | |
|             'freight_id': self.id, | |
|             'date': self.order_date, | |
|             'loading_port_id': self.loading_port_id.id, | |
|             'discharging_port_id': self.discharging_port_id.id, | |
|             'agent_id': self.agent_id.id, | |
|         }) | |
|         result = { | |
|             'name': 'action.name', | |
|             'type': 'ir.actions.act_window', | |
|             'views': [[False, 'form']], | |
|             'target': 'current', | |
|             'res_id': clearance.id, | |
|             'res_model': 'custom.clearance', | |
|         } | |
|         self.clearance = True | |
|         return result | |
| 
 | |
|     def get_custom_clearance(self): | |
|         """Get custom clearance""" | |
|         self.ensure_one() | |
|         return { | |
|             'type': 'ir.actions.act_window', | |
|             'name': 'Custom Clearance', | |
|             'view_mode': 'tree,form', | |
|             'res_model': 'custom.clearance', | |
|             'domain': [('freight_id', '=', self.id)], | |
|             'context': "{'create': False}" | |
|         } | |
| 
 | |
|     def track_order(self): | |
|         """Track the order""" | |
|         self.ensure_one() | |
|         return { | |
|             'type': 'ir.actions.act_window', | |
|             'name': 'Received/Delivered', | |
|             'view_mode': 'form', | |
|             'target': 'new', | |
|             'res_model': 'freight.order.track', | |
|             'context': { | |
|                 'default_freight_id': self.id | |
|             } | |
|         } | |
| 
 | |
|     def create_invoice(self): | |
|         """Create invoice""" | |
|         lines = [] | |
|         if self.order_ids: | |
|             for order in self.order_ids: | |
|                 value = (0, 0, { | |
|                     'name': order.product_id.name, | |
|                     'price_unit': order.price, | |
|                     'quantity': order.volume + order.weight, | |
|                 }) | |
|                 lines.append(value) | |
| 
 | |
|         if self.route_ids: | |
|             for route in self.route_ids: | |
|                 value = (0, 0, { | |
|                     'name': route.operation_id.name, | |
|                     'price_unit': route.sale, | |
|                 }) | |
|                 lines.append(value) | |
| 
 | |
|         if self.service_ids: | |
|             for service in self.service_ids: | |
|                 value = (0, 0, { | |
|                     'name': service.service_id.name, | |
|                     'price_unit': service.sale, | |
|                     'quantity': service.qty | |
|                 }) | |
|                 lines.append(value) | |
| 
 | |
|         invoice_line = { | |
|             'move_type': 'out_invoice', | |
|             'partner_id': self.shipper_id.id, | |
|             'invoice_user_id': self.env.user.id, | |
|             'invoice_origin': self.name, | |
|             'ref': self.name, | |
|             'invoice_line_ids': lines, | |
|         } | |
|         inv = self.env['account.move'].create(invoice_line) | |
|         result = { | |
|             'name': 'action.name', | |
|             'type': 'ir.actions.act_window', | |
|             'views': [[False, 'form']], | |
|             'target': 'current', | |
|             'res_id': inv.id, | |
|             'res_model': 'account.move', | |
|         } | |
|         self.state = 'invoice' | |
|         return result | |
| 
 | |
|     def action_cancel(self): | |
|         """Cancel the record""" | |
|         if self.state == 'draft' and self.state == 'submit': | |
|             self.state = 'cancel' | |
|         else: | |
|             raise ValidationError("You can't cancel this order") | |
| 
 | |
|     def get_invoice(self): | |
|         """View the invoice""" | |
|         self.ensure_one() | |
|         return { | |
|             'type': 'ir.actions.act_window', | |
|             'name': 'Invoice', | |
|             'view_mode': 'tree,form', | |
|             'res_model': 'account.move', | |
|             'domain': [('ref', '=', self.name)], | |
|             'context': "{'create': False}" | |
|         } | |
| 
 | |
|     @api.depends('name') | |
|     def compute_count(self): | |
|         """Compute custom clearance and account move's count""" | |
|         for rec in self: | |
|             if rec.env['custom.clearance'].search([('freight_id', '=', rec.id)]): | |
|                 rec.clearance_count = rec.env['custom.clearance'].search_count( | |
|                     [('freight_id', '=', rec.id)]) | |
|             else: | |
|                 rec.clearance_count = 0 | |
|             if rec.env['account.move'].search([('ref', '=', rec.name)]): | |
|                 rec.invoice_count = rec.env['account.move'].search_count( | |
|                     [('ref', '=', rec.name)]) | |
|             else: | |
|                 rec.invoice_count = 0 | |
| 
 | |
|     def action_submit(self): | |
|         """Submitting order""" | |
|         for rec in self: | |
|             rec.state = 'submit' | |
|             base_url = self.env['ir.config_parameter'].sudo().get_param( | |
|                 'web.base.url') | |
|             Urls = urls.url_join(base_url, 'web#id=%(id)s&model=freight.order&view_type=form' % {'id': self.id}) | |
| 
 | |
|             mail_content = _('Hi %s,<br>' | |
|                              'The Freight Order %s is Submitted' | |
|                              '<div style = "text-align: center; ' | |
|                              'margin-top: 16px;"><a href = "%s"' | |
|                              'style = "padding: 5px 10px; font-size: 12px; ' | |
|                              'line-height: 18px; color: #FFFFFF; ' | |
|                              'border-color:#875A7B;text-decoration: none; ' | |
|                              'display: inline-block; margin-bottom: 0px; ' | |
|                              'font-weight: 400;text-align: center; ' | |
|                              'vertical-align: middle; cursor: pointer; ' | |
|                              'white-space: nowrap; background-image: none; ' | |
|                              'background-color: #875A7B; ' | |
|                              'border: 1px solid #875A7B; border-radius:3px;">' | |
|                              'View %s</a></div>' | |
|                              ) % (rec.agent_id.name, rec.name, Urls, rec.name) | |
|             email_to = self.env['res.partner'].search([ | |
|                 ('id', 'in', (self.shipper_id.id, self.consignee_id.id, | |
|                               self.agent_id.id))]) | |
|             for mail in email_to: | |
|                 main_content = { | |
|                     'subject': _('Freight Order %s is Submitted') % self.name, | |
|                     'author_id': self.env.user.partner_id.id, | |
|                     'body_html': mail_content, | |
|                     'email_to': mail.email | |
|                 } | |
|                 mail_id = self.env['mail.mail'].create(main_content) | |
|                 mail_id.mail_message_id.body = mail_content | |
|                 mail_id.send() | |
| 
 | |
|     def action_confirm(self): | |
|         """Confirm order""" | |
|         for rec in self: | |
|             clearance = self.env['custom.clearance'].search([ | |
|                 ('freight_id', '=', self.id)]) | |
|             if clearance: | |
|                 if clearance.state == 'confirm': | |
|                     rec.state = 'confirm' | |
|                     base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') | |
|                     Urls = urls.url_join(base_url, 'web#id=%(id)s&model=freight.order&view_type=form' % {'id': self.id}) | |
|                     mail_content = _('Hi %s,<br> ' | |
|                                      'The Freight Order %s is Confirmed ' | |
|                                      '<div style = "text-align: center; ' | |
|                                      'margin-top: 16px;"><a href = "%s"' | |
|                                      'style = "padding: 5px 10px; ' | |
|                                      'font-size: 12px; line-height: 18px; ' | |
|                                      'color: #FFFFFF; border-color:#875A7B; ' | |
|                                      'text-decoration: none; ' | |
|                                      'display: inline-block; ' | |
|                                      'margin-bottom: 0px; font-weight: 400;' | |
|                                      'text-align: center; ' | |
|                                      'vertical-align: middle; ' | |
|                                      'cursor: pointer; white-space: nowrap; ' | |
|                                      'background-image: none; ' | |
|                                      'background-color: #875A7B; ' | |
|                                      'border: 1px solid #875A7B; ' | |
|                                      'border-radius:3px;">' | |
|                                      'View %s</a></div>' | |
|                                      ) % (rec.agent_id.name, rec.name, | |
|                                           Urls, rec.name) | |
|                     email_to = self.env['res.partner'].search([ | |
|                         ('id', 'in', (self.shipper_id.id, | |
|                                       self.consignee_id.id, self.agent_id.id))]) | |
|                     for mail in email_to: | |
|                         main_content = { | |
|                             'subject': _('Freight Order %s is Confirmed') % self.name, | |
|                             'author_id': self.env.user.partner_id.id, | |
|                             'body_html': mail_content, | |
|                             'email_to': mail.email | |
|                         } | |
|                         mail_id = self.env['mail.mail'].create(main_content) | |
|                         mail_id.mail_message_id.body = mail_content | |
|                         mail_id.send() | |
|                 elif clearance.state == 'draft': | |
|                     raise ValidationError("the custom clearance ' %s ' is " | |
|                                           "not confirmed" % clearance.name) | |
|             else: | |
|                 raise ValidationError("Create a custom clearance for %s" % rec.name) | |
| 
 | |
|             for line in rec.order_ids: | |
|                 line.container_id.state = 'reserve' | |
| 
 | |
|     def action_done(self): | |
|         """Mark order as done""" | |
|         for rec in self: | |
|             base_url = self.env['ir.config_parameter'].sudo().get_param( | |
|                 'web.base.url') | |
|             Urls = urls.url_join(base_url, 'web#id=%(id)s&model=freight.order&view_type=form' % {'id': self.id}) | |
| 
 | |
|             mail_content = _('Hi %s,<br>' | |
|                              'The Freight Order %s is Completed' | |
|                              '<div style = "text-align: center; ' | |
|                              'margin-top: 16px;"><a href = "%s"' | |
|                              'style = "padding: 5px 10px; font-size: 12px; ' | |
|                              'line-height: 18px; color: #FFFFFF; ' | |
|                              'border-color:#875A7B;text-decoration: none; ' | |
|                              'display: inline-block; ' | |
|                              'margin-bottom: 0px; font-weight: 400;' | |
|                              'text-align: center; vertical-align: middle; ' | |
|                              'cursor: pointer; white-space: nowrap; ' | |
|                              'background-image: none; ' | |
|                              'background-color: #875A7B; ' | |
|                              'border: 1px solid #875A7B; border-radius:3px;">' | |
|                              'View %s</a></div>' | |
|                              ) % (rec.agent_id.name, rec.name, Urls, rec.name) | |
|             email_to = self.env['res.partner'].search([ | |
|                 ('id', 'in', (self.shipper_id.id, self.consignee_id.id, | |
|                               self.agent_id.id))]) | |
|             for mail in email_to: | |
|                 main_content = { | |
|                     'subject': _('Freight Order %s is completed') % self.name, | |
|                     'author_id': self.env.user.partner_id.id, | |
|                     'body_html': mail_content, | |
|                     'email_to': mail.email | |
|                 } | |
|                 mail_id = self.env['mail.mail'].create(main_content) | |
|                 mail_id.mail_message_id.body = mail_content | |
|                 mail_id.send() | |
|             self.state = 'done' | |
| 
 | |
|             for line in rec.order_ids: | |
|                 line.container_id.state = 'available' | |
| 
 | |
| 
 | |
| class FreightOrderLine(models.Model): | |
|     _name = 'freight.order.line' | |
| 
 | |
|     order_id = fields.Many2one('freight.order') | |
|     container_id = fields.Many2one('freight.container', string='Container', | |
|                                    domain="[('state', '=', 'available')]") | |
|     product_id = fields.Many2one('product.product', string='Goods') | |
|     billing_type = fields.Selection([('weight', 'Weight'), | |
|                                      ('volume', 'Volume')], string="Billing On") | |
|     pricing_id = fields.Many2one('freight.price', string='Pricing') | |
|     price = fields.Float('Unit Price') | |
|     total_price = fields.Float('Total Price') | |
|     volume = fields.Float('Volume') | |
|     weight = fields.Float('Weight') | |
| 
 | |
|     @api.constrains('weight') | |
|     def _check_weight(self): | |
|         """Checking the weight of containers""" | |
|         for rec in self: | |
|             if rec.container_id and rec.billing_type: | |
|                 if rec.billing_type == 'weight': | |
|                     if rec.container_id.weight < rec.weight: | |
|                         raise ValidationError( | |
|                             'The weight is must be less ' | |
|                             'than or equal to %s' % (rec.container_id.weight)) | |
| 
 | |
|     @api.constrains('volume') | |
|     def _check_volume(self): | |
|         """Checking the volume of containers""" | |
|         for rec in self: | |
|             if rec.container_id and rec.billing_type: | |
|                 if rec.billing_type == 'volume': | |
|                     if rec.container_id.volume < rec.volume: | |
|                         raise ValidationError( | |
|                             'The volume is must be less ' | |
|                             'than or equal to %s' % (rec.container_id.volume)) | |
| 
 | |
|     @api.onchange('pricing_id', 'billing_type') | |
|     def onchange_price(self): | |
|         """Calculate the weight and volume of container""" | |
|         for rec in self: | |
|             if rec.billing_type == 'weight': | |
|                 rec.volume = 0.00 | |
|                 rec.price = rec.pricing_id.weight | |
|             elif rec.billing_type == 'volume': | |
|                 rec.weight = 0.00 | |
|                 rec.price = rec.pricing_id.volume | |
| 
 | |
|     @api.onchange('pricing_id', 'billing_type', 'volume', 'weight') | |
|     def onchange_total_price(self): | |
|         """Calculate sub total price""" | |
|         for rec in self: | |
|             if rec.billing_type and rec.pricing_id: | |
|                 if rec.billing_type == 'weight': | |
|                     rec.total_price = rec.weight * rec.price | |
|                 elif rec.billing_type == 'volume': | |
|                     rec.total_price = rec.volume * rec.price | |
| 
 | |
| 
 | |
| class FreightOrderRouteLine(models.Model): | |
|     _name = 'freight.order.routes.line' | |
| 
 | |
|     route_id = fields.Many2one('freight.order') | |
|     operation_id = fields.Many2one('freight.routes', required=True) | |
|     source_loc = fields.Many2one('freight.port', 'Source Location') | |
|     destination_loc = fields.Many2one('freight.port', 'Destination Location') | |
|     transport_type = fields.Selection([('land', 'Land'), ('air', 'Air'), | |
|                                        ('water', 'Water')], "Transport", | |
|                                       required=True) | |
|     sale = fields.Float('Sale') | |
| 
 | |
|     @api.onchange('operation_id', 'transport_type') | |
|     def _onchange_operation_id(self): | |
|         """calculate the price of route operation""" | |
|         for rec in self: | |
|             if rec.operation_id and rec.transport_type: | |
|                 if rec.transport_type == 'land': | |
|                     rec.sale = rec.operation_id.land_sale | |
|                 elif rec.transport_type == 'air': | |
|                     rec.sale = rec.operation_id.air_sale | |
|                 elif rec.transport_type == 'water': | |
|                     rec.sale = rec.operation_id.water_sale | |
| 
 | |
| 
 | |
| class FreightOrderServiceLine(models.Model): | |
|     _name = 'freight.order.service' | |
| 
 | |
|     line_id = fields.Many2one('freight.order') | |
|     service_id = fields.Many2one('freight.service', required=True) | |
|     partner_id = fields.Many2one('res.partner', string="Vendor") | |
|     qty = fields.Float('Quantity') | |
|     cost = fields.Float('Cost') | |
|     sale = fields.Float('Sale') | |
|     total_sale = fields.Float('Total Sale') | |
| 
 | |
|     @api.onchange('service_id', 'partner_id') | |
|     def _onchange_partner_id(self): | |
|         """Calculate the price of services""" | |
|         for rec in self: | |
|             if rec.service_id: | |
|                 if rec.partner_id: | |
|                     if rec.service_id.line_ids: | |
|                         for service in rec.service_id.line_ids: | |
|                             if rec.partner_id == service.partner_id: | |
|                                 rec.sale = service.sale | |
|                             else: | |
|                                 rec.sale = rec.service_id.sale_price | |
|                     else: | |
|                         rec.sale = rec.service_id.sale_price | |
|                 else: | |
|                     rec.sale = rec.service_id.sale_price | |
| 
 | |
|     @api.onchange('qty', 'sale') | |
|     def _onchange_qty(self): | |
|         """Calculate the subtotal of route operation""" | |
|         for rec in self: | |
|             rec.total_sale = rec.qty * rec.sale | |
| 
 | |
| 
 | |
| class Tracking(models.Model): | |
|     _name = 'freight.track' | |
| 
 | |
|     source_loc = fields.Many2one('freight.port', 'Source Location') | |
|     destination_loc = fields.Many2one('freight.port', 'Destination Location') | |
|     transport_type = fields.Selection([('land', 'Land'), ('air', 'Air'), | |
|                                        ('water', 'Water')], "Transport") | |
|     track_id = fields.Many2one('freight.order') | |
|     date = fields.Date('Date') | |
|     type = fields.Selection([('received', 'Received'), | |
|                              ('delivered', 'Delivered')], 'Received/Delivered')
 | |
| 
 |