# Author Mufti Muntasir Ahmed 20-06-2021

from odoo import api, fields, tools, models, _
from odoo.exceptions import UserError, ValidationError
import datetime
import json
from datetime import datetime
from odoo.osv import osv
import requests

class ManifestProcess(models.Model):
    _name = 'manifest.process'
    _description = 'Manifest Process'
    _order = 'id desc'

    READONLY_STATES = {
        'purchase': [('readonly', True)],
        'done': [('readonly', True)],
        'cancel': [('readonly', True)],
    }

    name = fields.Char('Manifest Number')
    third_party_delivery = fields.Boolean('3PL Delivery')
    partner_id = fields.Many2one('res.partner', string='Courier')

    vehicle_number = fields.Char('Vehicle Number')
    assign_name = fields.Char('Assign To')
    assigned_user_ids = fields.Many2one('res.users', string='Assigned User')
    manifest_date = fields.Datetime('Manifest Date')
    remarks = fields.Text('Any Remarks')
    manifest_amount = fields.Float(string='Total Manifest Amount')
    cash_journal_id = fields.Many2one('account.journal', string='Cash Journal', domain="[('type', 'in', ('bank', 'cash'))]")
    bank_journal_id = fields.Many2one('account.journal', string='Bank Journal', domain="[('type', 'in', ('bank', 'cash'))]")

    warehouse_id = fields.Many2one('stock.warehouse', string='Warehouse')
    manifest_process_line_ids = fields.One2many('manifest.process.line', 'manifest_process_id',
                                                string='Manifest Process lines')
    state = fields.Selection([
        ('pending', 'Pending'),
        ('confirm', 'Confirmation'),
        ('delivered', 'Delivered & Not Paid'),
        ('closed', 'Paid & Closed'),
        ('cancel', 'Cancelled'),
    ], string='Status', readonly=True, copy=False, index=True, tracking=3, default='pending')
    total_return_amount = fields.Float('Total Return Amount')
    total_ndr_amount = fields.Float('Total NDR Amount')
    total_received_amount = fields.Float('Total Receiving Amount')
    total_cash_amount = fields.Float('Total Cash Amount')
    total_receivable_amount = fields.Float('Total Delivered Amount')
    total_credit_amount = fields.Float('Total Credit Amount')
    total_paid_amount = fields.Float('Total Advance/Paid Amount')

    @api.model
    def create(self, vals):
        res = super(ManifestProcess, self).create(vals)
        pick_number = "MP0" + str(res.id)
        res.name = pick_number
        return res

    def create_delivery_from_manifest(self):

        # record = super(wms_manifest_process, self).confirm_wms_manifest(cr, uid, ids, context=context)

        # wms_man = self.env["wms.manifest.process"].browse(cr, uid, ids, context=context)
        inv_obj = self.env["account.move"]
        wms_man_out = self.env["wms.manifest.outbound"]

        # for line in wms_man.picking_line:
        invoice_id = self.ids
        inv = inv_obj.browse(invoice_id)

        name = self.env.context.get('name')  # Magento Ref
        man_name = self.env.context.get('man_name')  # Manifest No
        delivery_date = self.env.context['delivery_date']

        if inv.date_invoice > delivery_date:
            raise osv.except_osv(_('Warning!'), _('Delivery date can not less than invoice date!'))
        out_data = {
            'name': name,
            'man_name': man_name,
            'delivery_date': delivery_date,
            'delivery_time': self.env.context['delivery_time'],
            'state': 'confirm',
            'confirm': True,
            'confirm_by': self.uid,
            'source': self.env.context.get('source') if self.env.context.get('source') else 'Web',
            'delivery_done_by': self.env.uid,
            'delivery_done_datetime': datetime.datetime.today(),
        }

        outbound_line_list = list()

        for inv_line in inv.invoice_line:
            if float(inv_line.quantity) > 0.00:
                outbound_line_list.append([0, False, {
                    'invoice_id': invoice_id[0],
                    'magento_no': name,
                    'description': str(inv_line.name),
                    'product_id': inv_line.product_id.id,
                    'amount': float(inv_line.price_subtotal),
                    'quantity': float(inv_line.quantity),
                    'delivered': float(inv_line.quantity)
                }])

        out_data['outbound_line'] = outbound_line_list

        wms_man_id = wms_man_out.create(out_data)
        wms_man_out.write(wms_man_id, {'state': 'confirm', 'confirm': True})

        return True

    def process_confirm(self, data):

        magento_no = data['name']
        query_for_SO = self.env['sale.order'].search([('client_order_ref', '=', magento_no)])

        if len(query_for_SO) > 0:

            sales = self.env['sale.order'].browse(query_for_SO)[0]

            sale_order = self.env["sale.order"]
            for so_item in sales:
                if so_item.state != 'cancel':
                    if so_item.delivered_amount == so_item.amount_total:
                        dispatch_wms_query = "UPDATE sale_order SET invoiced_dispatch=TRUE  WHERE id='{1}'".format(self.uid,
                                                                                                                   so_item.id)
                        self.env.cr.execute(dispatch_wms_query)
                        self.env.cr.commit()
                        # sale_order.action_status(cr, uid, [so_item.id, ], 'dispatched', context=context)
                    else:
                        dispatch_wms_query = "UPDATE sale_order SET partially_invoiced_dispatch=TRUE  WHERE id='{1}'".format(
                            so_item.id)
                        self.env.cr.execute(dispatch_wms_query)
                        self.env.cr.commit()
                        # sale_order.action_status(cr, uid, [so_item.id, ], 'partially_dispatched', context=context)
        # --------------------------------------------------

        # if the last invoice then set state confirm
        man_pro_obj = self.env["wms.manifest.line"]
        inv_obj = self.env["account.move"]
        man_pro_line_list = man_pro_obj.search([('invoice_id', '=', data['invoice_id']), ('reschedule', '=', False)])
        man_process_line = man_pro_obj.browse(man_pro_line_list)

        man_process = man_process_line.wms_manifest_id

        if man_process.id is False and data.has_key('wms_manifest_id'):
            man_process = data['wms_manifest_id']

        total_invoices = len(man_process.picking_line)
        processed_inv = 0

        for man_p in man_process.picking_line:

            if str(man_p.manifest_out_status) == "assigned":
                processed_inv += 1

        if total_invoices == processed_inv:

            # call confirm. otherwise "sms" will not go
            # self.env['wms.manifest.process'].confirm_wms_manifest(cr, uid, [man_process.id], context=context)

            try:

                confirm_wms_query = "UPDATE wms_manifest_process SET state='confirm', confirm_by='{0}', confirm_time='{1}' WHERE id='{2}'".format(
                    str(fields.datetime.now()), man_process.id)
                self.env.cr.execute(confirm_wms_query)
                self.env.cr.commit()

                wms_man_lin_query = "UPDATE wms_manifest_line SET delivery_date='{0}', deliver_time='{1}' WHERE invoice_id='{2}' AND magento_no='{3}'".format(
                    data['delivery_date'], data['delivery_time'], data['invoice_id'], data['name'])
                self.env.cr.execute(wms_man_lin_query)
                self.env.cr.commit()

            except:
                pass
        else:

            wms_man_lin_query = "UPDATE wms_manifest_line SET delivery_date='{0}', deliver_time='{1}' WHERE invoice_id='{2}' AND magento_no='{3}'".format(
                data['delivery_date'], data['delivery_time'], data['invoice_id'], data['name'])
            self.env.cr.execute(wms_man_lin_query)
            self.env.cr.commit()

        return True

    def confirm_manifest_process(self):

        shipment_inv_id_lists = []
        for rec in self:
            if rec.state == 'pending':
                for itm_line in self.manifest_process_line_ids:
                    shipment_inv_id_lists.append(itm_line.invoice_id.id)
                    mob_no=''
                    if itm_line.invoice_id.partner_shipping_id.phone:
                        mob_no = itm_line.invoice_id.partner_shipping_id.phone
                    if itm_line.invoice_id.partner_shipping_id.mobile:
                        mob_no = itm_line.invoice_id.partner_shipping_id.mobile


                    sms_text = "Dear valued customer, your order %23"+str(itm_line.order_no)+" has been shipped. You will receive your order within 24 hours. Thank you for choosing Walcart."
                    if len(mob_no)>10:
                        ## Send SMS Section
                        mobile_no = mob_no
                        try:

                            basic_urls = "https://api.mobireach.com.bd/SendTextMessage?Username=walton_api&Password=Walton20@19&From=walcart&To="
                            params = mobile_no + "&Message=" + sms_text
                            final_url = basic_urls + params
                            r = requests.get(final_url)
                        except:
                            pass


                        ## Ends here the SMS

                    self._cr.execute("update account_move set in_shipment = 'True' where id in %s", (tuple(shipment_inv_id_lists),))
                self._cr.commit()

                rec.write({'state': 'confirm'})





        return True

    def cancel_manifest_process(self):
        for rec in self:
            if rec.state == 'pending':
                rec.write({'state': 'cancel'})
            else:
                raise ValidationError(_('You can not cancel at this state'))
        return True

    def pay_total(self):


        cash_journal_id = self.cash_journal_id.id
        bank_journal_id = self.bank_journal_id.id
        today_date = fields.Date.today()

        for man_line in self.manifest_process_line_ids:
            tmp_dict={
            'journal_id': cash_journal_id,
            'payment_date': today_date,
            'payment_method_id': 1
        }
            if 'paid' in str(man_line.payment_type):
                tmp_dict['journal_id']=bank_journal_id

            if man_line.delivered_amount> 0 and man_line.full_delivered == True:
                invoice_ids = [man_line.invoice_id.id]
                self.env['account.payment.register'].with_context(active_ids=invoice_ids).create(tmp_dict).create_payments()

        update_manifest_status_query = "update manifest_process set state='closed' where id='{0}'".format(
            self.id)
        self._cr.execute(update_manifest_status_query)
        self._cr.commit()




        return True

    def calculate_total(self):

        total_delivered = 0
        total_return_amount = 0
        total_ndr_amount = 0
        total_advance_amount = 0
        total_credit_amount = 0
        total_cash_amount = 0
        total_received_amount = 0
        all_manifest_did_not_taken_action = False
        for items in self.manifest_process_line_ids:
            if items.manifest_out_status != 'assigned':
                all_manifest_did_not_taken_action=True
                break


        if all_manifest_did_not_taken_action == True:
            raise osv.except_osv(_('Warning!'), _('All Orders must be Delivered/Returned/Rescheduled'))
        for items in self.manifest_process_line_ids:
            total_delivered += items.delivered_amount
            total_return_amount += items.return_amount
            total_ndr_amount += items.ndr_amount

            if 'paid' in items.payment_type:
                total_advance_amount +=items.delivered_amount
            else:
                total_cash_amount +=items.delivered_amount
        query = "update manifest_process set total_return_amount=%s,total_ndr_amount=%s,total_received_amount=%s," \
                "total_cash_amount=%s,total_receivable_amount=%s,total_credit_amount=%s ,total_paid_amount=%s where id=%s"
        self._cr.execute(query,([total_return_amount,total_ndr_amount,total_received_amount,total_cash_amount,
              total_received_amount,total_credit_amount,total_advance_amount, self.id]))

        self._cr.commit()

        update_manifest_status_query = "update manifest_process set state='delivered' where id='{0}'".format(
            self.id)
        self._cr.execute(update_manifest_status_query)
        self._cr.commit()

        return True


class ManifestProcessLine(models.Model):
    _name = 'manifest.process.line'
    _description = 'Manifest Process Line'

    manifest_process_id = fields.Many2one('manifest.process', string='Product Picking Entry', index=True, required=True,
                                          readonly=True, auto_join=True, ondelete="cascade")
    order_no = fields.Char('Order No')
    magento_no = fields.Char("Magento Number")
    invoice_id = fields.Many2one('account.move', string='Invoice ID')
    customer_id = fields.Many2one('res.partner', string='Customer')
    phone_no = fields.Char('Phone No')
    address_line = fields.Char('Address')
    payment_type = fields.Char('Payment Type')
    amount = fields.Float('Amount')
    area = fields.Char('Area')
    status = fields.Char('Status')

    manifest_out_status = fields.Char('Manifest Out Status')
    delivery_date = fields.Date('Delivery Date')
    deliver_time = fields.Char('Delivery Time')
    reschedule = fields.Boolean('Reschedule')
    rm_name = fields.Char('RM Name')
    rm_phone = fields.Char('RM Phone')
    full_delivered = fields.Boolean('Full Delivered')
    partial_delivered = fields.Boolean('Partial Delivered')
    full_return = fields.Boolean('Full Return')

    delivered_amount = fields.Float('Delivered Amount')
    return_amount = fields.Float('Return Amount')
    ndr_amount = fields.Float('NDR Amount')
    journal_id = fields.Many2one('account.move', 'Journal ID')



    @api.model
    def create(self, vals):

        record = super(ManifestProcessLine, self).create(vals)

        try:

            so_obj = self.env["sale.order"]
            so_list = so_obj.search(self._cr, self._uid, [('client_order_ref', '=', record.magento_no)])

            for so in so_obj.browse(self._cr, self._uid, so_list):

                if so.custom_salesperson:
                    record.rm_name = so.custom_salesperson.name
                    record.rm_phone = so.custom_salesperson.mobile
                record.priority_customer = so.new_customer
        except:
            pass

        return record

    def reschedule_invoice_delivery(self):

        wms_man_line = self.browse()

        ndr_pro_obj = self.env["ndr.process"]
        wms_man_pro = self.env["wms.manifest.process"]
        man_line_obj = self.env['wms.manifest.line']
        inv_obj = self.env["account.move"]
        so_obj = self.env["sale.order"]
        inv_list = inv_obj.search([('id', '=', wms_man_line.invoice_id)])
        inv = inv_obj.browse(inv_list)
        so_list = so_obj.search([('client_order_ref', '=', str(inv.name))])
        so = so_obj.browse(so_list)

        if ndr_pro_obj.search([('invoice_id', '=', inv.id)]) and wms_man_line.reschedule:
            raise osv.except_osv(_('Warning!'), _('NDR Process Already done!!! Can not do again!'))

        if inv.number:
            ndr_data = dict()
            ndr_data['invoice_number'] = inv.number
            ndr_data['invoice'] = inv
            ndr_data['magento_number'] = str(inv.name)
            ndr_data['order_number'] = so.name
            ndr_data['order_id'] = so.id
            ndr_data['state'] = 'draft'
            ndr_data['ndr_reason'] = 'Created from outbound'
            ndr_data['source'] = self.env.context['source']

            inv_line_list = list()

            for invoice_line in inv.invoice_line:
                if invoice_line.quantity > 0.00:
                    inv_line_list.append([0, False, {
                        'product': str(invoice_line.name),
                        'product_id': int(invoice_line.product_id.id),
                        'product_ean': str(invoice_line.product_id.ean13) if invoice_line.product_id.ean13 else '',
                        'quantity': invoice_line.quantity,
                        # 'received_quantity': 0,

                    }])

            ndr_data['ndr_process_line'] = inv_line_list

            # ndr.process
            ndr_pro_id = ndr_pro_obj.create(ndr_data)
            ndr_pro_obj.confirm_ndr([ndr_pro_id])

            # status assigned
            data = dict()
            data['invoice_id'] = inv.id
            data['name'] = str(inv.name)
            data['delivery_date'] = datetime.datetime.now().strftime('%Y-%m-%d')
            data['delivery_time'] = ''
            data['wms_manifest_id'] = man_line_obj.browse().wms_manifest_id

            source = self.env.context.get('source') if self.env.context.get('source') else 'Web'
            delivery_done_by = self.env.uid
            delivery_done_datetime = datetime.datetime.today()

            man_line_obj.write({'manifest_out_status': 'assigned', 'reschedule': True, 'source': source,
                                'delivery_done_by': delivery_done_by,
                                'delivery_done_datetime': delivery_done_datetime})

            wms_man_pro.process_confirm(data)

        else:
            raise osv.except_osv(_('Warning!'), _('The invoice is not validate yet!!! Please validate the invoice'))

        return True

    def action_invoice_full_delivered(self):
        context = None

        manifest_line = self.browse()

        context['name'] = str(manifest_line.magento_no)
        context['man_name'] = str(manifest_line.wms_manifest_id.name)
        context['invoice_id'] = manifest_line.invoice_id
        context['magento_no'] = str(manifest_line.magento_no)
        context['manifest_line_id'] = manifest_line.id
        context['source'] = context.get('source') if context.get('source') else 'Web'

        source = context['source']
        delivery_done_by = self.env.uid
        delivery_done_datetime = datetime.datetime.today()

        self.env["wms.manifest.process"].create_delivery_from_manifest([manifest_line.invoice_id])

        self.write({'manifest_out_status': 'assigned', 'full_delivered': True, 'source': source,
                    'delivery_done_by': delivery_done_by,
                    'delivery_done_datetime': delivery_done_datetime})

        # --------------------------------------------------
        data = dict()
        data['name'] = str(manifest_line.magento_no)
        data['invoice_id'] = manifest_line.invoice_id
        data['delivery_date'] = context['delivery_date']
        data['delivery_time'] = context['delivery_time']
        self.env['wms.manifest.process'].process_confirm(data)
        # --------------------------------------------------

        return True


class AccountInvoice(models.Model):
    _inherit = 'account.move'

    delivery_date = fields.Date('Delivery Date')
    delivered = fields.Boolean('Delivered')
    full_return = fields.Boolean('Full return')
    ndr = fields.Boolean('NDR')
    loaded = fields.Boolean('Order Loaded')
    in_shipment = fields.Boolean('Order In Shipment')
    total_ndr = fields.Integer('Total NDR Count')



