from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
import logging
from datetime import datetime
from collections import defaultdict
class GudangService(models.Model):
_name = "gudang.service"
_description = "Gudang Service"
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'id asc'
name = fields.Char('Name', readonly=True)
partner_id = fields.Many2one('res.partner', string='Customer', readonly=True)
vendor_id = fields.Many2one('res.partner', string='Vendor Service', required=True)
origin = fields.Many2one('sale.order', string='Origin SO', required=True, domain=[('state', 'in', ['done', 'sale'])])
schedule_date = fields.Date(
string="Schedule Date",
required=True,
tracking=True
)
start_date = fields.Datetime(
string="Date Processed",
copy=False,
tracking=True
)
create_date = fields.Datetime(string='Create Date', copy=False, tracking=True, default=fields.Datetime.now())
done_date = fields.Datetime(string='Date Done', copy=False, tracking=True)
gudang_service_lines = fields.One2many('gudang.service.line', 'gudang_service_id', string='Gudang Service Lines')
# unprocessed_date = fields.Char(
# string='Unprocessed Since',
# compute='_compute_unprocessed_date'
# )
remaining_date = fields.Char(
compute='_compute_remaining_date',
string='Date Status'
)
state = fields.Selection([
('draft', 'Backlog'),
('received_from_cust', 'Received From Customer'),
('sent_to_vendor', 'Sent to Service Vendor'),
('received_from_vendor', 'Received From Service Vendor'),
('delivered_to_cust', 'Delivered to Customer'),
('cancel', 'Cancel')], default='draft', tracking=True)
cancel_reason = fields.Text('Cancel Reason', tracking=True)
@api.constrains('gudang_service_lines')
def _check_qty(self):
for rec in self:
if not rec.origin:
continue
so_qty_map = {
line.product_id.id: line.product_uom_qty
for line in rec.origin.order_line
}
for line in rec.gudang_service_lines:
if line.quantity <= 0:
raise ValidationError(
f"Quantity for product {line.product_id.display_name} cannot be 0 or negative."
)
so_qty = so_qty_map.get(line.product_id.id, 0)
if line.quantity > so_qty:
raise ValidationError(
f"Quantity for product {line.product_id.display_name} "
f"cannot exceed SO quantity ({so_qty})."
)
@api.constrains('state', 'schedule_date')
def _check_edit_after_sent(self):
for rec in self:
if rec.state in ['sent_to_vendor', 'received_from_vendor', 'delivered_to_cust']:
if rec._origin.schedule_date != rec.schedule_date:
raise ValidationError("Schedule cannot be modified after sent to vendor")
def _send_logistic_notification(self):
group = self.env.ref('indoteknik_custom.group_role_logistic', raise_if_not_found=False)
if not group:
return
users = group.users
# MD
md = self.env['res.users'].browse([3425, 4801, 1036])
# send to logistic and MD
users = users | md
if not users:
return
# Logistic users to be excluded
excluded_users = [7, 17098, 216, 28, 15710]
for rec in self:
for user in users:
if user.id in excluded_users:
continue
self.env['mail.activity'].create({
'res_model_id': self.env['ir.model']._get_id('gudang.service'),
'res_id': rec.id,
'activity_type_id': self.env.ref('mail.mail_activity_data_todo').id,
'user_id': user.id,
'summary': 'Gudang Service On Progress',
'note': _(
'Ada Jadwal Service Barang di Document %s Jadwal Service 📅 %s'
) % (rec.name, rec.schedule_date),
# 'date_deadline': fields.Date.today(),
})
# kirim ke private message odoo
channel = self.env['mail.channel'].channel_get([self.env.user.partner_id.id, user.partner_id.id]).get('id')
if not channel:
continue
res = self.env['mail.channel'].browse(channel)
res.with_user(self.env.user.browse(25)).message_post(body=_('Ada Jadwal Service Barang di Document %s Jadwal Service 📅 %s') % (rec.name, rec.schedule_date), message_type='comment', subtype_xmlid='mail.mt_comment')
@api.model
def cron_notify_onprogress_gudang_service(self):
records = self.search([
('state', 'in', ['draft', 'received_from_cust']),
])
if records:
records._send_logistic_notification()
@api.depends('schedule_date', 'create_date')
def _compute_remaining_date(self):
today = fields.Date.today()
for rec in self:
if not rec.schedule_date:
rec.remaining_date = "-"
continue
base_date = rec.create_date.date() if rec.create_date else today
schedule = rec.schedule_date
days = (schedule - base_date).days
if days > 0:
rec.remaining_date = _("In %s days") % days
elif days == 0:
rec.remaining_date = _("Today")
else:
rec.remaining_date = _("Overdue %s days") % abs(days)
def action_submit(self):
for rec in self:
if rec.state == 'draft':
rec.state = 'received_from_cust'
elif rec.state == 'received_from_cust':
rec.state = 'sent_to_vendor'
rec.start_date = fields.Datetime.now()
elif rec.state == 'sent_to_vendor':
rec.state = 'received_from_vendor'
def action_done(self):
for rec in self:
if rec.state != 'received_from_vendor':
raise UserError("Only 'Received From Vendor' state can be set to Done")
rec.activity_ids.unlink()
rec.write({
'state': 'delivered_to_cust',
'done_date': fields.Datetime.now()
})
def action_draft(self):
"""Reset to draft state"""
for rec in self:
rec.cancel_reason = False
if rec.state == 'cancel':
rec.write({'state': 'draft'})
else:
raise UserError("Only Canceled Record Can Be Reset To Draft")
def action_cancel(self):
for rec in self:
activities = self.env['mail.activity'].search([
('res_id', '=', rec.id),
('res_model', '=', 'gudang.service'),
])
activities.unlink()
if rec.state == 'delivered_to_cust':
raise UserError("You cannot cancel a done record")
if not rec.cancel_reason:
raise UserError("Cancel Reason must be filled")
rec.start_date = False
rec.done_date = False
rec.state = 'cancel'
@api.model
def create(self, vals):
# sequence
if not vals.get('name') or vals['name'] == 'New':
vals['name'] = self.env['ir.sequence'].next_by_code('gudang.service')
# partner dari SO
so = self.env['sale.order'].browse(vals['origin'])
vals['partner_id'] = so.partner_id.id
res = super(GudangService, self).create(vals)
res._send_logistic_notification()
return res
def write(self, vals):
if vals.get('origin'):
so = self.env['sale.order'].browse(vals['origin'])
vals['partner_id'] = so.partner_id.id
return super(GudangService, self).write(vals)
@api.onchange('origin')
def _onchange_origin(self):
if not self.origin:
self.gudang_service_lines = [(5, 0, 0)]
return
self.partner_id = self.origin.partner_id
lines = []
for line in self.origin.order_line:
lines.append((0, 0, {
'product_id': line.product_id.id,
'quantity': line.product_uom_qty,
'origin_so': self.origin.id,
}))
# hapus line lama lalu isi baru
self.gudang_service_lines = [(5, 0, 0)] + lines
class GudangServiceLine(models.Model):
_name = "gudang.service.line"
_inherit = ['mail.thread', 'mail.activity.mixin']
product_id = fields.Many2one('product.product', string='Product')
quantity = fields.Float(string='Quantity')
origin_so = fields.Many2one('sale.order', string='Origin SO')
gudang_service_id = fields.Many2one('gudang.service', string='Gudang Service ID')