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.
359 lines
18 KiB
359 lines
18 KiB
# -*- coding: utf-8 -*-
|
|
###############################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
|
|
# Author: Cybrosys Techno Solutions (<https://www.cybrosys.com>)
|
|
#
|
|
# This program is under the terms of Odoo Proprietary License v1.0 (OPL-1)
|
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the
|
|
# Software or modified copies of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING
|
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
# DEALINGS IN THE SOFTWARE.
|
|
#
|
|
###############################################################################
|
|
from datetime import date
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class CourierRequest(models.Model):
|
|
"""This is for creating courier requests"""
|
|
_name = 'courier.request'
|
|
_description = "Courier Request"
|
|
_inherit = ["mail.thread", "mail.activity.mixin"]
|
|
|
|
state = fields.Selection(
|
|
selection=[('new', 'New'), ('collected', 'Collected'),
|
|
('invoiced', 'Invoiced'), ('dispatched', 'Dispatched'),
|
|
('in_transit', 'In Transit'),
|
|
('arrived_at_destination', 'Arrived At Destination'),
|
|
('out_for_delivery', 'Out For Delivery'),
|
|
('delivered', 'Delivered'), ('cancelled', 'Cancelled')],
|
|
string="State", default='new', help="State of the courier request")
|
|
name = fields.Char(string='Name', readonly=True, copy=False,
|
|
default='New', help="Sequence number")
|
|
sender_id = fields.Many2one('res.partner',
|
|
string="Sender Name",
|
|
help="Name of The Sender", required=True)
|
|
sender_address = fields.Char(string="Sender Address",
|
|
help="Address Of The Sender")
|
|
sender_mobile_number = fields.Char(string="Sender Phone Number",
|
|
help="Mobile Number Of The Sender",
|
|
related='sender_id.phone',
|
|
readonly=False,
|
|
required=True)
|
|
sender_email = fields.Char(string="Sender Email",
|
|
help="Email Of The Sender",
|
|
related='sender_id.email',
|
|
readonly=False, required=True)
|
|
sender_street = fields.Char(string="Sender Street",
|
|
related='sender_id.street', readonly=False,
|
|
help="Street of the sender")
|
|
sender_street2 = fields.Char(string="Sender Second Street",
|
|
related='sender_id.street2', readonly=False,
|
|
help="Second street of the sender")
|
|
sender_city = fields.Char(string="Sender City", related='sender_id.city',
|
|
readonly=False,
|
|
help="City of the sender")
|
|
sender_state_id = fields.Many2one('res.country.state',
|
|
string="Sender State",
|
|
related='sender_id.state_id',
|
|
readonly=False,
|
|
domain="[('country_id', '=?', "
|
|
"sender_address_country_id)]",
|
|
help="State of the sender")
|
|
sender_zip = fields.Char(string="Sender Zip", related='sender_id.zip',
|
|
help="Zip of the sender")
|
|
sender_address_country_id = fields.Many2one('res.country',
|
|
string="Sender Country "
|
|
"Address",
|
|
related='sender_id.country_id',
|
|
readonly=False,
|
|
help="Country of the sender")
|
|
receiver_id = fields.Many2one('res.partner',
|
|
string="Receiver Name",
|
|
help="Name of the receiver", required=True)
|
|
receiver_address = fields.Char(string="Receiver Address",
|
|
help="Address of the receiver")
|
|
receiver_street = fields.Char(string="Receiver Street",
|
|
related='receiver_id.street', readonly=False,
|
|
help="Street of the receiver")
|
|
receiver_street2 = fields.Char(string="Receiver Second Street",
|
|
related='receiver_id.street2',
|
|
readonly=False,
|
|
help="Second street of the receiver")
|
|
receiver_city = fields.Char(string="Receiver City",
|
|
related='receiver_id.city', readonly=False,
|
|
help="City of the receiver")
|
|
receiver_state_id = fields.Many2one('res.country.state',
|
|
string="Receiver State",
|
|
related='receiver_id.state_id',
|
|
readonly=False,
|
|
domain="[('country_id', '=?', "
|
|
"receiver_address_country_id)]",
|
|
help="State of the receiver")
|
|
receiver_zip = fields.Char(string="Receiver Zip",
|
|
related='receiver_id.zip',
|
|
readonly=False,
|
|
help="Zip of the receiver")
|
|
receiver_address_country_id = fields.Many2one('res.country',
|
|
string="Receiver Country "
|
|
"Address",
|
|
related='receiver_id.'
|
|
'country_id',
|
|
readonly=False,
|
|
help="Country of the "
|
|
"receiver")
|
|
receiver_mobile_number = fields.Char(string="Receiver Phone Number",
|
|
help="Mobile Number Of The Receiver",
|
|
related='receiver_id.phone',
|
|
readonly=False,
|
|
required=True)
|
|
receiver_email = fields.Char(string="Receiver Email", help="Email Of The "
|
|
"Receiver",
|
|
related='receiver_id.email',
|
|
readonly=False, required=True)
|
|
registration_date = fields.Date(string="Registration Date",
|
|
help="Courier Registration Date",
|
|
default=date.today(),
|
|
readonly=True)
|
|
delivery_date = fields.Date(string="Delivery Date",
|
|
help="Courier Delivery Date", required=True)
|
|
total_kilometres = fields.Float(string="Total Kilometres",
|
|
help="Total Kilometers To Courier Sends",
|
|
required=True)
|
|
distance_amount = fields.Monetary(string="Distance Amount",
|
|
compute='_compute_distance_amount',
|
|
store=True,
|
|
help="Distance amount based on the "
|
|
"distance")
|
|
responsible_user_id = fields.Many2one('res.users',
|
|
default=lambda self: self.env.user,
|
|
string="Responsible User",
|
|
help="Responsible User Of This "
|
|
"Courier",
|
|
readonly=True)
|
|
type_id = fields.Many2one('courier.type', string="Type",
|
|
required=True, help="Courier type")
|
|
tag_ids = fields.Many2many('courier.tag', string="Tag",
|
|
help="Courier tags")
|
|
l_w_h_id = fields.Many2one('courier.dimension.price',
|
|
string="L x W x H", required=True,
|
|
help="Courier box size")
|
|
volumetric_weight = fields.Float(string="Volumetric Weight",
|
|
related='l_w_h_id.volumetric_weight',
|
|
help="Weight of the courier")
|
|
volumetric_weight_price = fields.Monetary(string="Volumetric Weight Price",
|
|
compute='_compute_volumetric_'
|
|
'weight_price',
|
|
help="Weight price of the"
|
|
" courier")
|
|
priority_id = fields.Many2one('courier.priority',
|
|
string="Priority", help="Courier priority")
|
|
priority_amount = fields.Monetary(string="Priority Amount",
|
|
compute='_compute_priority_amount',
|
|
help="Courier priority amount based on "
|
|
"priority")
|
|
category_id = fields.Many2one('courier.category',
|
|
string="Category", required=True,
|
|
help="Courier category")
|
|
description = fields.Char(string="Description", help="Add description")
|
|
internal_note = fields.Char(string="Internal Note", help="Add internal "
|
|
"note")
|
|
total_courier_charges = fields.Float(string="Total Courier Charges",
|
|
readonly=True,
|
|
help="The total courier charges")
|
|
total = fields.Monetary(string="Total", compute='_compute_total',
|
|
help="Total")
|
|
company_id = fields.Many2one('res.company', string="Company",
|
|
required=True,
|
|
default=lambda self: self.env.company,
|
|
readonly=True, help="Choose company")
|
|
currency_id = fields.Many2one("res.currency", string='Currency',
|
|
related='company_id.currency_id',
|
|
help="Company currency")
|
|
courier_details_ids = fields.One2many('courier.detail',
|
|
'courier_requests_id',
|
|
string="Courier Details",
|
|
help="Courier details")
|
|
|
|
def action_collected(self):
|
|
"""This will change the state to collected or give validation error"""
|
|
for record in self:
|
|
if record.courier_details_ids:
|
|
self.state = 'collected'
|
|
else:
|
|
raise ValidationError(_(
|
|
'You Need To Add A Line Before Collecting'))
|
|
|
|
def action_dispatched(self):
|
|
"""This will change the state to dispatched"""
|
|
self.state = 'dispatched'
|
|
|
|
def action_in_transit(self):
|
|
"""This will change the state to in transit"""
|
|
self.state = 'in_transit'
|
|
|
|
def action_arrived_at_destination(self):
|
|
"""This will change the state to arrived at destination"""
|
|
self.state = 'arrived_at_destination'
|
|
|
|
def action_out_for_delivery(self):
|
|
"""This will change the state to out for delivery"""
|
|
self.state = 'out_for_delivery'
|
|
|
|
def action_delivered(self):
|
|
"""This will change the state to delivered"""
|
|
self.state = 'delivered'
|
|
|
|
def action_cancelled(self):
|
|
"""This will change the state to cancelled"""
|
|
self.state = 'cancelled'
|
|
|
|
@api.onchange('delivery_date')
|
|
def _onchange_delivery_date(self):
|
|
"""If the delivery date is smaller than registration date. It gives
|
|
a validation error"""
|
|
if self.delivery_date and self.delivery_date <= self.registration_date:
|
|
raise ValidationError(_('Delivery Is Not Possible On This Date'))
|
|
|
|
@api.onchange('total_kilometres')
|
|
def _onchange_total_kilometres(self):
|
|
"""If the total kilometres is smaller than one.It gives a validation"""
|
|
if self.total_kilometres and self.total_kilometres < 1:
|
|
raise ValidationError(_('Delivery Is Not Available'))
|
|
|
|
def action_create_invoice(self):
|
|
"""Creating invoices for corresponding courier request"""
|
|
self.state = 'invoiced'
|
|
for rec in self:
|
|
invoice_id = self.env['account.move'].create({
|
|
'move_type': 'out_invoice',
|
|
'partner_id': rec.sender_id.id,
|
|
'invoice_date': rec.registration_date,
|
|
'invoice_user_id': rec.responsible_user_id.id,
|
|
'courier_ref_id': rec.id
|
|
})
|
|
for courier_order_line in self.courier_details_ids:
|
|
invoice_id.write({
|
|
'invoice_line_ids': [(0, 0, {
|
|
'product_id': courier_order_line.product_id.id,
|
|
'quantity': 1,
|
|
'price_unit': courier_order_line.weight_price,
|
|
})]
|
|
})
|
|
if self.l_w_h_id:
|
|
invoice_id.write({
|
|
'invoice_line_ids': [(0, 0, {
|
|
'product_id': self.env.ref(
|
|
'courier_management.'
|
|
'volumetric_weight_charges_product').id,
|
|
})]
|
|
})
|
|
if self.priority_id:
|
|
invoice_id.write({
|
|
'invoice_line_ids': [(0, 0, {
|
|
'product_id': self.env.ref(
|
|
'courier_management.'
|
|
'additional_charges_priority_product').id,
|
|
})]
|
|
})
|
|
if self.distance_amount:
|
|
invoice_id.write({
|
|
'invoice_line_ids': [(0, 0, {
|
|
'product_id': self.env.ref(
|
|
'courier_management.distance_charges_product').id,
|
|
})]
|
|
})
|
|
invoice_id.action_post()
|
|
|
|
def action_view_invoices(self):
|
|
"""It returns the Invoices tree view"""
|
|
return {
|
|
'name': 'Invoice',
|
|
'view_mode': 'list,form',
|
|
'res_model': 'account.move',
|
|
'type': 'ir.actions.act_window',
|
|
'domain': [('courier_ref_id', '=', self.id)],
|
|
'context': "{'create': False}"
|
|
}
|
|
|
|
@api.onchange('courier_details_ids')
|
|
def _onchange_courier_details_ids(self):
|
|
"""Returns the total courier charges"""
|
|
total = 0
|
|
courier = self.courier_details_ids
|
|
total_charge = courier.mapped('sub_total')
|
|
for record in range(0, len(total_charge)):
|
|
total = total + total_charge[record]
|
|
self.total_courier_charges = total
|
|
|
|
@api.depends('priority_amount', 'distance_amount',
|
|
'total_courier_charges', 'volumetric_weight_price')
|
|
def _compute_total(self):
|
|
"""Computes the total"""
|
|
self.total = (self.priority_amount + self.distance_amount
|
|
+ self.total_courier_charges +
|
|
self.volumetric_weight_price)
|
|
|
|
@api.depends('total_kilometres')
|
|
def _compute_distance_amount(self):
|
|
"""Returns the distance amount"""
|
|
prices = []
|
|
self.distance_amount = False
|
|
for record in self.env['courier.distance.price'].search(
|
|
[('minimum_distance', '<=', self.total_kilometres),
|
|
('maximum_distance', '>=', self.total_kilometres)]):
|
|
prices.append(record.price)
|
|
if prices:
|
|
self.distance_amount = min(prices)
|
|
else:
|
|
distances = self.env['courier.distance.price'].search([])
|
|
minimum_distances = [rec.minimum_distance for rec in distances]
|
|
maximum_distances = [rec.maximum_distance for rec in distances]
|
|
prices = [rec.price for rec in distances]
|
|
|
|
if self.total_kilometres < min(minimum_distances):
|
|
self.distance_amount = min(prices)
|
|
elif self.total_kilometres > max(maximum_distances):
|
|
self.distance_amount = max(prices)
|
|
|
|
distance = self.env['product.product'].browse(
|
|
[self.env.ref('courier_management.distance_charges_product').id])
|
|
distance.list_price = self.distance_amount
|
|
|
|
@api.depends('priority_id')
|
|
def _compute_priority_amount(self):
|
|
"""Returns the priority amount based on priority"""
|
|
self.priority_amount = self.priority_id.charges
|
|
priority = self.env['product.product'].browse(
|
|
[self.env.ref(
|
|
'courier_management.additional_charges_priority_product').id])
|
|
priority.list_price = self.priority_amount
|
|
|
|
@api.depends('l_w_h_id')
|
|
def _compute_volumetric_weight_price(self):
|
|
"""Returns the volumetric weight price"""
|
|
self.volumetric_weight_price = self.l_w_h_id.price
|
|
volume = self.env['product.product'].browse(
|
|
[self.env.ref(
|
|
'courier_management.volumetric_weight_charges_product').id])
|
|
volume.list_price = self.volumetric_weight_price
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
"""This is used to get the Courier sequence number"""
|
|
for vals in vals_list:
|
|
if vals.get('name', 'New') == 'New':
|
|
vals['name'] = self.env['ir.sequence'].next_by_code(
|
|
'courier.request') or 'New'
|
|
result = super(CourierRequest, self).create(vals_list)
|
|
return result
|
|
|