Example #1
0
class sale_order_line(osv.osv):

    def _number_packages(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        for line in self.browse(cr, uid, ids, context=context):
            try:
                res[line.id] = int((line.product_uom_qty+line.product_packaging.qty-0.0001) / line.product_packaging.qty)
            except:
                res[line.id] = 1
        return res

    _inherit = 'sale.order.line'
    _columns = { 
        'delay': fields.float('Delivery Lead Time', required=True, help="Number of days between the order confirmation and the shipping of the products to the customer", readonly=True, states={'draft': [('readonly', False)]}),
        'procurement_id': fields.many2one('procurement.order', 'Procurement'),
        'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties', readonly=True, states={'draft': [('readonly', False)]}),
        'product_packaging': fields.many2one('product.packaging', 'Packaging'),
        'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True),
        'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'),
    }
    _defaults = {
        'delay': 0.0,
        'product_packaging': False,
    }

    def _get_line_qty(self, cr, uid, line, context=None):
        if line.procurement_id and not (line.order_id.invoice_quantity=='order'):
            return self.pool.get('procurement.order').quantity_get(cr, uid,
                   line.procurement_id.id, context=context)
        else:
            return super(sale_order_line, self)._get_line_qty(cr, uid, line, context=context)


    def _get_line_uom(self, cr, uid, line, context=None):
        if line.procurement_id and not (line.order_id.invoice_quantity=='order'):
            return self.pool.get('procurement.order').uom_get(cr, uid,
                    line.procurement_id.id, context=context)
        else:
            return super(sale_order_line, self)._get_line_uom(cr, uid, line, context=context)

    def button_cancel(self, cr, uid, ids, context=None):
        res = super(sale_order_line, self).button_cancel(cr, uid, ids, context=context)
        for line in self.browse(cr, uid, ids, context=context):
            for move_line in line.move_ids:
                if move_line.state != 'cancel':
                    raise osv.except_osv(
                            _('Cannot cancel sales order line!'),
                            _('You must first cancel stock moves attached to this sales order line.'))   
        return res

    def copy_data(self, cr, uid, id, default=None, context=None):
        if not default:
            default = {}
        default.update({'move_ids': []})
        return super(sale_order_line, self).copy_data(cr, uid, id, default, context=context)

    def product_packaging_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False,
                                   partner_id=False, packaging=False, flag=False, context=None):
        if not product:
            return {'value': {'product_packaging': False}}
        product_obj = self.pool.get('product.product')
        product_uom_obj = self.pool.get('product.uom')
        pack_obj = self.pool.get('product.packaging')
        warning = {}
        result = {}
        warning_msgs = ''
        if flag:
            res = self.product_id_change(cr, uid, ids, pricelist=pricelist,
                    product=product, qty=qty, uom=uom, partner_id=partner_id,
                    packaging=packaging, flag=False, context=context)
            warning_msgs = res.get('warning') and res['warning']['message']

        products = product_obj.browse(cr, uid, product, context=context)
        if not products.packaging:
            packaging = result['product_packaging'] = False
        elif not packaging and products.packaging and not flag:
            packaging = products.packaging[0].id
            result['product_packaging'] = packaging

        if packaging:
            default_uom = products.uom_id and products.uom_id.id
            pack = pack_obj.browse(cr, uid, packaging, context=context)
            q = product_uom_obj._compute_qty(cr, uid, uom, pack.qty, default_uom)
#            qty = qty - qty % q + q
            if qty and (q and not (qty % q) == 0):
                ean = pack.ean or _('(n/a)')
                qty_pack = pack.qty
                type_ul = pack.ul
                if not warning_msgs:
                    warn_msg = _("You selected a quantity of %d Units.\n"
                                "But it's not compatible with the selected packaging.\n"
                                "Here is a proposition of quantities according to the packaging:\n"
                                "EAN: %s Quantity: %s Type of ul: %s") % \
                                    (qty, ean, qty_pack, type_ul.name)
                    warning_msgs += _("Picking Information ! : ") + warn_msg + "\n\n"
                warning = {
                       'title': _('Configuration Error!'),
                       'message': warning_msgs
                }
            result['product_uom_qty'] = qty

        return {'value': result, 'warning': warning}

    def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
            uom=False, qty_uos=0, uos=False, name='', partner_id=False,
            lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
        context = context or {}
        product_uom_obj = self.pool.get('product.uom')
        partner_obj = self.pool.get('res.partner')
        product_obj = self.pool.get('product.product')
        warning = {}
        res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,
            uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
            lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)

        if not product:
            res['value'].update({'product_packaging': False})
            return res

        #update of result obtained in super function
        product_obj = product_obj.browse(cr, uid, product, context=context)
        res['value']['delay'] = (product_obj.sale_delay or 0.0)
        res['value']['type'] = product_obj.procure_method

        #check if product is available, and if not: raise an error
        uom2 = False
        if uom:
            uom2 = product_uom_obj.browse(cr, uid, uom)
            if product_obj.uom_id.category_id.id != uom2.category_id.id:
                uom = False
        if not uom2:
            uom2 = product_obj.uom_id

        # Calling product_packaging_change function after updating UoM
        res_packing = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context)
        res['value'].update(res_packing.get('value', {}))
        warning_msgs = res_packing.get('warning') and res_packing['warning']['message'] or ''
        compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding)
        if (product_obj.type=='product') and int(compare_qty) == -1 \
          and (product_obj.procure_method=='make_to_stock'):
            warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \
                    (qty, uom2 and uom2.name or product_obj.uom_id.name,
                     max(0,product_obj.virtual_available), product_obj.uom_id.name,
                     max(0,product_obj.qty_available), product_obj.uom_id.name)
            warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n"

        #update of warning messages
        if warning_msgs:
            warning = {
                       'title': _('Configuration Error!'),
                       'message' : warning_msgs
                    }
        res.update({'warning': warning})
        return res
Example #2
0
    def _save_file(self, path, b64_file):
        """Save a file encoded in base 64"""
        self._check_filestore(path)
        with open(path, 'w') as ofile:
            ofile.write(base64.b64decode(b64_file))
        return True

    def _set_image(self, cr, uid, id, name, value, arg, context=None):
        image = self.browse(cr, uid, id, context=context)
        full_path = self._image_path(cr, uid, image, context=context)
        if full_path:
            return self._save_file(full_path, value)
        return self.write(cr, uid, id, {'file_db_store' : value}, context=context)

    _columns = {
        'name':fields.char('Image Title', size=100, required=True),
        'extention': fields.char('file extention', size=6),
        'link':fields.boolean('Link?', help="Images can be linked from files on your file system or remote (Preferred)"),
        'file_db_store':fields.binary('Image stored in database'),
        'file':fields.function(_get_image, fnct_inv=_set_image, type="binary", filters='*.png,*.jpg,*.gif'),
        'url':fields.char('File Location', size=250),
        'comments':fields.text('Comments'),
        'product_id':fields.many2one('product.product', 'Product')
        }
    _defaults = {
        'link': lambda *a: False,
        }
    _sql_constraints = [('uniq_name_product_id', 'UNIQUE(product_id, name)',
                         _('A product can have only one image with the same name'))]

Example #3
0
                user_id = res[0]
        elif conf['create_user']:
            _logger.debug("Creating new Odoo user \"%s\" from LDAP" % login)
            user_obj = self.pool['res.users']
            values = self.map_ldap_attributes(cr, uid, conf, login, ldap_entry)
            if conf['user']:
                values['active'] = True
                user_id = user_obj.copy(cr, SUPERUSER_ID, conf['user'],
                                        default=values)
            else:
                user_id = user_obj.create(cr, SUPERUSER_ID, values)
        return user_id

    _columns = {
        'sequence': fields.integer('Sequence'),
        'company': fields.many2one('res.company', 'Company', required=True,
            ondelete='cascade'),
        'ldap_server': fields.char('LDAP Server address', required=True),
        'ldap_server_port': fields.integer('LDAP Server port', required=True),
        'ldap_binddn': fields.char('LDAP binddn', 
            help=("The user account on the LDAP server that is used to query "
                  "the directory. Leave empty to connect anonymously.")),
        'ldap_password': fields.char('LDAP password',
            help=("The password of the user account on the LDAP server that is "
                  "used to query the directory.")),
        'ldap_filter': fields.char('LDAP filter', required=True),
        'ldap_base': fields.char('LDAP base', required=True),
        'user': fields.many2one('res.users', 'Template User',
            help="User to copy when creating new users"),
        'create_user': fields.boolean('Create user',
            help="Automatically create local user accounts for new users authenticating via LDAP"),
        'ldap_tls': fields.boolean('Use TLS',
Example #4
0
                    try:
                        price = grid_obj.get_price(cr, uid, carrier_grid, order, time.strftime("%Y-%m-%d"), context)
                        available = True
                    except osv.except_osv, e:
                        # no suitable delivery method found, probably configuration error
                        _logger.error("Carrier %s: %s\n%s" % (carrier.name, e.name, e.value))
                        price = 0.0
                else:
                    price = 0.0
            res[carrier.id] = {"price": price, "available": available}
        return res

    _columns = {
        "name": fields.char("Delivery Method", required=True),
        "partner_id": fields.many2one(
            "res.partner", "Transport Company", required=True, help="The partner that is doing the delivery service."
        ),
        "product_id": fields.many2one("product.product", "Delivery Product", required=True),
        "grids_id": fields.one2many("delivery.grid", "carrier_id", "Delivery Grids"),
        "available": fields.function(
            get_price,
            string="Available",
            type="boolean",
            multi="price",
            help="Is the carrier method possible with the current order.",
        ),
        "price": fields.function(get_price, string="Price", multi="price"),
        "active": fields.boolean(
            "Active",
            help="If the active field is set to False, it will allow you to hide the delivery carrier without removing it.",
        ),
        }

    
    def onchange_shipping_service(self, cr, uid, ids, ups_shipper_id=False, context=None):
         vals = {}
         service_type_ids = []
         if ups_shipper_id:
             shipper_obj = self.pool.get('ups.account.shipping').browse(cr, uid, ups_shipper_id)
             for shipper in shipper_obj.ups_shipping_service_ids:
                 service_type_ids.append(shipper.id)
         domain = [('id', 'in', service_type_ids)]
         return {'domain': {'ups_service_id': domain}}
    
    _columns= {
        'ship_company_code': fields.selection(_get_company_code, 'Ship Company', method=True, size=64),
        'ups_shipper_id': fields.many2one('ups.account.shipping', 'Shipper'),
        'ups_service_id': fields.many2one('ups.shipping.service.type', 'Shipping Service'),
        'ups_pickup_type': fields.selection([
            ('01', 'Daily Pickup'),
            ('03', 'Customer Counter'),
            ('06', 'One Time Pickup'),
            ('07', 'On Call Air'),
            ('11', 'Suggested Retail Rates'),
            ('19', 'Letter Center'),
            ('20', 'Air Service Center'),
        ], 'Pickup Type'),
        'ups_packaging_type': fields.many2one('shipping.package.type','Packaging Type'),
        'partner_id': fields.many2one('res.partner', 'Customer'),
        'partner_shipping_id': fields.many2one('res.partner', 'Shipping Address'),
        }
shipping_rate_wizard()
>>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d
        'cc_number':fields.char('Credit Card Number', size=256),
        'cc_v':fields.char('Card Code Verification', size=3),
        'cc_e_d_month':fields.char('Expiration Date MM', size=32),
        'cc_e_d_year':fields.char('Expiration Date YY', size=32),
        'cc_comment':fields.char('Comment', size=128,),
        'cc_auth_code':fields.char('Authorization Code', size=32),
        'cc_save_card_details':fields.boolean('Save Credit Card details'),
        'cc_ecommerce_sale':fields.boolean('Ecommerce sale'),
        'cc_p_authorize':fields.boolean('Pre-authorize'),
        'cc_charge':fields.boolean('Charge'),
        'cc_info_hide':fields.boolean('Credit Info Hide'),
        'cc_status':fields.text('Status Message'),
        'cc_details_autofill':fields.boolean('Credit Card Details Auto Fill'),
        'cc_reseller':fields.boolean('Reseller'),
        'rel_sale_order_id':fields.many2one('sale.order', 'Related Sale Order'),
        'cc_trans_id':fields.char('Transaction ID', size=128),
        'cc_bank':fields.many2one('res.bank', 'Bank'),
        'cc_details':fields.many2one('res.partner.bank', 'Bank'),
        'cc_length':fields.integer('CC Length'),
        'cc_transaction':fields.boolean('Transaction Done'),
        'key':fields.char('Encryption Key', size=1024,
                          help="The Key used to Encrypt the Credit Card Number"),
        'cc_refund_amt':fields.float('Refund Amt'),
        'is_charged': fields.boolean('CreditCard Charged'),
        'trans_history_ids': fields.one2many('transaction.details', 'voucher_id', 'Transaction History')
    }
    _defaults = {
        'cc_info_hide': lambda * a: True,
        'cc_p_authorize': lambda * a: True,
    }
Example #7
0
                if 'Expecting: CERTIFICATE' in e[0]:
                    raise osv.except_osv(
                        _('Wrong Certificate file format'),
                        _('Be sure you have BEGIN CERTIFICATE string in'
                          ' your first line.'))
                else:
                    raise osv.except_osv(
                        _('Unknown error'),
                        _('X509 return this message:\n %s') % e[0])

            wz.wsafip_request_id.write({'state': 'confirmed'})

    _name = 'l10n_ar_wsafip.loadcert_config'
    _inherit = 'res.config'
    _columns = {
        'wsafip_request_id': fields.many2one(
            'crypto.certificate', 'Certificate Request', required=True),
        'wsafip_request_file': fields.binary(
            'Download Signed Certificate Request', readonly=True),
        'wsafip_request_filename': fields.char(
            'Filename', readonly=True),
        'wsafip_response_file': fields.binary(
            'Upload Certificate', required=True),
    }
    _defaults = {
        'wsafip_request_filename': 'request.csr',
    }
l10n_ar_wsafip_loadcert_config()


# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
Example #8
0
class sale_order_line(orm.Model):
    _inherit = "sale.order.line"

    def _prepare_order_line_invoice_line(self, cr, uid, line, account_id=False, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        vals = super(sale_order_line, self)._prepare_order_line_invoice_line(cr, uid, line, account_id, context)
        if vals:
            vals.update({'origin_document': 'sale.order.line, {line_id}'.format(line_id=line.id)})
        return vals

    def _delivered_qty(self, cr, uid, ids, field_name, arg, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        res = {}
        for line in self.browse(cr, uid, ids, context=context):
            qty = 0

            for move in line.move_ids:
                if move.state == 'done':
                    qty += move.product_qty

            res[line.id] = qty
        return res

    def _product_available(self, cr, uid, ids, field_names=None, arg=False, context=None):
        """ Finds the incoming and outgoing quantity of product.
        @return: Dictionary of values
        """
        context = context or self.pool['res.users'].context_get(cr, uid)
        res = {}
        # if line.order_id:
        #     context['warehouse'] = self.order_id.shop_id.warehouse_id.id

        for line in self.browse(cr, uid, ids, context):
            res[line.id] = {
                'qty_available': line.product_id and line.product_id.type != 'service' and line.product_id.qty_available or False,
                'virtual_available': line.product_id and line.product_id.type != 'service' and line.product_id.virtual_available or False}
        return res

    # overwrite of a funcion inside sale_margin
    def product_id_change(self, cr, uid, ids, pricelist, product_id, qty=0,
                          uom=False, qty_uos=0, uos=False, name='', partner_id=False,
                          lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False,
                          flag=False, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        context.update(error_on_available=False)
        res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product_id, qty=qty,
                                                             uom=uom, qty_uos=qty_uos, uos=uos, name=name,
                                                             partner_id=partner_id,
                                                             lang=lang, update_tax=update_tax, date_order=date_order,
                                                             packaging=packaging, fiscal_position=fiscal_position,
                                                             flag=flag, context=context)
        if not pricelist:
            return res

        frm_cur = self.pool['res.users'].browse(cr, uid, uid, context).company_id.currency_id.id
        to_cur = self.pool['product.pricelist'].browse(cr, uid, [pricelist], context)[0].currency_id.id
        if product_id:
            product = self.pool['product.product'].browse(cr, uid, product_id, context)
            price = self.pool['res.currency'].compute(cr, uid, frm_cur, to_cur, product.cost_price, round=False)
            res['value'].update({
                'purchase_price': price,
                'product_type': product.type
            })

        return res

    _columns = {
        'order_id': fields.many2one('sale.order', 'Order Reference', ondelete='cascade', select=True, readonly=True,
                                    states={'draft': [('readonly', False)]}),
        'readonly_price_unit': fields.related('order_id', 'company_id', 'readonly_price_unit', type='boolean',
                                              string=_('Readonly Price Unit'), store=False, readonly=True),
        'delivered_qty': fields.function(_delivered_qty, digits_compute=dp.get_precision('Product UoM'),
                                         string='Delivered Qty'),
        'qty_available': fields.function(_product_available, multi='qty_available',
                                         type='float', digits_compute=dp.get_precision('Product UoM'),
                                         string='Quantity On Hand'),
        'virtual_available': fields.function(_product_available, multi='qty_available',
                                             type='float', digits_compute=dp.get_precision('Product UoM'),
                                             string='Quantity Available'),
        'product_type': fields.char('Product type', size=64),
    }

    _defaults = {
        'readonly_price_unit': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid,
                                                                                            context).company_id.readonly_price_unit,
        'order_id': lambda self, cr, uid, context: context.get('default_sale_order', False) or False
    }

    def default_get(self, cr, uid, fields, context=None):
        """
        """
        if not context:
            context = self.pool['res.users'].context_get(cr, uid)
        res = super(sale_order_line, self).default_get(cr, uid, fields, context=context)
        if not res.get('tax_id', False):
            fpos_obj = self.pool['account.fiscal.position']
            product_default_get = self.pool['product.product'].default_get(cr, uid, ['taxes_id', 'uom_id'])
            taxes = product_default_get.get('taxes_id', False)
            if taxes:
                taxes = self.pool['account.tax'].browse(cr, uid, taxes, context)

                if context.get('fiscal_position', False):
                    fpos = fpos_obj.browse(cr, uid, context['fiscal_position'], context)
                    if taxes:
                        tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
                    else:
                        tax_id = []
                else:
                    if taxes:
                        tax_id = [line.id for line in taxes]
                    else:
                        tax_id = []

                res.update({
                    'tax_id': [(6, 0, tax_id)],
                })
        uom_id = product_default_get.get('uom_id', False)
        if uom_id:
            res.update({
                    'product_uom': uom_id
            })
        return res
Example #9
0
class ids_emp_info_change(osv.osv):
    
    _name = 'ids.emp.info.change'
    _description = "Employee Information Change"
    
    def _employee_get(self, cr, uid, context=None): 
        """Gets default value from the hr.employee. """       
        emp_id = context.get('default_employee_id', False)
        if emp_id:
            return emp_id
        ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)], context=context)
        if ids:
            return ids[0]
        return False           
    _columns = {
                'name':fields.char('Name', size=100),
                'division_id':fields.many2one('division', 'Division'),
                'emp_code':fields.char('Employee Code', size=100),
                'employee_id':fields.many2one('hr.employee','Employee Name'),
                'req_date':fields.date('Request Date'),
                'date':fields.date('Date'),
                'marital': fields.selection([('single', 'Single'), ('married', 'Married'), ('widower', 'Widower'), ('divorced', 'Divorced')], 'Marital Status'),
                'doa':fields.date('Date Of Anniversary'),
                'email':fields.char('Email',  size=240),
                'blood_groups':fields.selection([('1','A+'),('2','B+'),('3','A-'),('4','B-'),('5','O+'),('6','O-'),('7','AB+'),('8','AB-')], 'Blood Group'),
                'mobile_no':fields.char('Mobile', size=240),
                'home_phone':fields.char('Home Phone', size=240),
                'local_address':fields.char('Local Address'),
                'pin_local':fields.char('Pin', size=100),
                'permanent_address':fields.char('Permanent Address'),
                'pin_permanent':fields.char('Pin', size=100),
                'weight':fields.char('Weight', size=100),
                'height':fields.char('Height', size=100),
                'passport_no':fields.char('Passport No.', size=100),
                'passport_till':fields.date('Passport Till'),
                'vehicle':fields.char('Vehicle'),
                'hobby':fields.char('Hobby'),
                'spouse_name':fields.char('Spouse Name'),
                'child_name1':fields.char('Child Name'),
                'dob1':fields.date('DOB'),
                'child_name2':fields.char('Child Name'),
                'dob2':fields.date('DOB'),
                'emerg_per_name':fields.char('Emergency Person Name'),
                'emerg_per_relation':fields.char('Emergency Person Relation'),
                'emerg_address':fields.char('Emergency Address'),
                'emerg_pin':fields.char('Emergency Pin'),
                'emerg_contact_no':fields.char('Emergency Contact Number'),
                'text1':fields.char('Text1'),
                'text2':fields.char('Text2'),
                'text3':fields.char('Text3'),
                'text4':fields.char('Text4'),
                'text5':fields.char('Text5'),
                'text6':fields.char('Text6'),
                'text7':fields.char('Text7'),
                'text8':fields.char('Text8'),
                'text9':fields.char('Text9'),
                'text10':fields.char('Text10'),
                'text11':fields.char('Text11'),
                'text12':fields.char('Text12'),
                'text13':fields.char('Text13'),
                'text14':fields.char('Text14'),
                'text15':fields.char('Text15'),
                'text16':fields.char('Text16'),
                'text17':fields.char('Text17'),
                'text18':fields.char('Text18'),
                'text19':fields.char('Text19'),
                'text20':fields.char('Text20'),
                'text21':fields.char('Text21'),
                'text22':fields.char('Text22'),
                'text23':fields.char('Text23'),
                'text24':fields.char('Text24'),
                'text25':fields.char('Text25'),
                'text26':fields.char('Text26'),
                'marital_prev': fields.selection([('single', 'Single'), ('married', 'Married'), ('widower', 'Widower'), ('divorced', 'Divorced')], 'Marital Status'),
                'doa_prev':fields.date('Date Of Anniversary'),
                'email_prev':fields.char('Email',  size=240),
                'blood_groups_prev':fields.selection([('1','A+'),('2','B+'),('3','A-'),('4','B-'),('5','O+'),('6','O-'),('7','AB+'),('8','AB-')], 'Blood Group'),
                'mobile_no_prev':fields.char('Mobile', size=240),
                'home_phone_prev':fields.char('Home Phone', size=240),
                'local_address_prev':fields.char('Local Address'),
                'pin_local_prev':fields.char('Pin', size=100),
                'permanent_address_prev':fields.char('Permanent Address'),
                'pin_permanent_prev':fields.char('Pin', size=100),
                'weight_prev':fields.char('Weight', size=100),
                'height_prev':fields.char('Height', size=100),
                'passport_no_prev':fields.char('Passport No.', size=100),
                'passport_till_prev':fields.date('Passport Till'),
                'vehicle_prev':fields.char('Vehicle'),
                'hobby_prev':fields.char('Hobby'),
                'spouse_name_prev':fields.char('Spouse Name'),
                'child_name1_prev':fields.char('Child Name'),
                'dob1_prev':fields.date('DOB'),
                'child_name2_prev':fields.char('Child Name'),
                'dob2_prev':fields.date('DOB'),
                'emerg_per_name_prev':fields.char('Emergency Person Name'),
                'emerg_per_relation_prev':fields.char('Emergency Person Relation'),
                'emerg_address_prev':fields.char('Emergency Address'),
                'emerg_pin_prev':fields.char('Emergency Pin'),
                'emerg_contact_no_prev':fields.char('Emergency Contact Number'),
                'state': fields.selection([
                                           ('draft', 'Draft'),
                                           ('submitted', 'Waiting For Approval'),
                                           ('validated', 'Approved'),            
                                           ('refused', 'Refused'),
                                           ],
                                          'Status', readonly=True,
                                          help='When the employee information change request is created the status is \'Draft\'.\n It is submitted by the employee and request is sent to Location HR, the status is \'submitted\'.\
                                          \nIf the Location Hr validate it, the status is \'Validated\'.\n If the Location Hr refuse it, the status is \'Refused\'.'),
                }
    
    _defaults = {
        'employee_id': _employee_get,
        'state': 'draft',
        'req_date': lambda *a: time.strftime("%Y-%m-%d"),
    }
    
    
    def unlink(self, cr, uid, ids, context=None):
        for item in self.browse(cr, uid, ids, context=context):
            if item.state not in ('draft'):
                raise osv.except_osv(_('Warning!'),_('You cannot delete a request which is not draft!'))
        return super(ids_emp_info_change, self).unlink(cr, uid, ids, context=context)
    
    def onchange_employee_id(self, cr, uid, ids, employee_id, context=None):
        """Get all the values associated with employee with onchange of employee id
            from hr.employee. """
        emp_code = ''
        marital = ''
        doa = ''
        email = ''
        blood_group = ''
        mobile_no = ''
        home_phone = ''
        local_address = ''
        pin_local = ''
        permanent_address = ''
        pin_permanent = ''
        weight = ''
        height = ''
        passport_no = ''
        passport_till = ''
        vehicle = ''
        hobby = ''
        spouse_name = ''
        child_name1 = ''
        dob1 = ''
        child_name2 = ''
        dob2 = ''
        emerg_per_name = ''
        emerg_per_relation = ''
        emerg_address = ''
        emerg_pin = ''
        emerg_contact_no = ''
        division_id=''
        obj_emp = self.pool.get('hr.employee')        
        res={}    
        if employee_id:
            record = obj_emp.browse(cr,uid,employee_id,context=context)            
            
            if record:    
                emp_code = record.emp_code
                marital = record.marital
                doa = record.marriage_date
                email = record.work_email
                blood_group = record.blood_groups
                mobile_no = record.mobile_phone
                home_phone = record.work_phone
                permanent_address = record.permanent_address
                weight = record.weight
                height = record.height
                passport_no = record.passport_id
                local_address = record.current_address
                division_id=record.division
                res = {'value': {
                                 'emp_code': emp_code,
                                 'marital': marital,
                                 'email': email,
                                 'blood_groups': blood_group,
                                 'mobile_no': mobile_no,
                                 'home_phone': home_phone,
                                 'permanent_address': permanent_address,
                                 'weight': weight,
                                 'height': height,
                                 'passport_no': passport_no,
                                 'local_address' : local_address,
                                 'doa' : doa,
                                 
                                 'marital_prev': marital,
                                 'email_prev': email,
                                 'blood_groups_prev': blood_group,
                                 'mobile_no_prev': mobile_no,
                                 'home_phone_prev': home_phone,
                                 'permanent_address_prev': permanent_address,
                                 'weight_prev': weight,
                                 'height_prev': height,
                                 'passport_no_prev': passport_no,
                                 'local_address_prev' : local_address,
                                 'doa_prev' : doa,
                                 'division_id': division_id
                                 
                                 
                                }
                       }
                      
        return res
    
    def submit(self, cr, uid, ids, context=None):
        """Submit the form to Location HR. """
        change=self.browse(cr, uid, ids, context=context)
        if change.marital<>change.marital_prev:
            self.write(cr, uid, ids, {'text1': 'Update'}, context=context)
        if change.email<>change.email_prev:
            self.write(cr, uid, ids, {'text2': 'Update'}, context=context)
        if change.mobile_no<>change.mobile_no_prev:
            self.write(cr, uid, ids, {'text3': 'Update'}, context=context)
        if change.local_address<>change.local_address_prev:
            self.write(cr, uid, ids, {'text4': 'Update'}, context=context)
        if change.permanent_address<>change.permanent_address_prev:
            self.write(cr, uid, ids, {'text5': 'Update'}, context=context)
        if change.weight<>change.weight_prev:
            self.write(cr, uid, ids, {'text6': 'Update'}, context=context)
        if change.passport_no<>change.passport_no_prev:
            self.write(cr, uid, ids, {'text7': 'Update'}, context=context)
        if change.vehicle<>change.vehicle_prev:
            self.write(cr, uid, ids, {'text8': 'Update'}, context=context)
        if change.child_name1<>change.child_name1_prev:
            self.write(cr, uid, ids, {'text9': 'Update'}, context=context)
        if change.child_name2<>change.child_name2_prev:
            self.write(cr, uid, ids, {'text10': 'Update'}, context=context)
        if change.emerg_per_name<>change.emerg_per_name_prev:
            self.write(cr, uid, ids, {'text11': 'Update'}, context=context)
        if change.emerg_address<>change.emerg_address_prev:
            self.write(cr, uid, ids, {'text12': 'Update'}, context=context)
        if change.emerg_contact_no<>change.emerg_contact_no_prev:
            self.write(cr, uid, ids, {'text13': 'Update'}, context=context)
        if change.doa<>change.doa_prev:
            self.write(cr, uid, ids, {'text14': 'Update'}, context=context)
        if change.blood_groups<>change.blood_groups_prev:
            self.write(cr, uid, ids, {'text15': 'Update'}, context=context)
        if change.home_phone<>change.home_phone_prev:
            self.write(cr, uid, ids, {'text16': 'Update'}, context=context)
        if change.pin_local<>change.pin_local_prev:
            self.write(cr, uid, ids, {'text17': 'Update'}, context=context)
        if change.pin_permanent<>change.pin_permanent_prev:
            self.write(cr, uid, ids, {'text18': 'Update'}, context=context)
        if change.height<>change.height_prev:
            self.write(cr, uid, ids, {'text19': 'Update'}, context=context)
        if change.passport_till<>change.passport_till_prev:
            self.write(cr, uid, ids, {'text20': 'Update'}, context=context)
        if change.hobby<>change.hobby_prev:
            self.write(cr, uid, ids, {'text21': 'Update'}, context=context)
        if change.dob1<>change.dob1_prev:
            self.write(cr, uid, ids, {'text22': 'Update'}, context=context)
        if change.dob2<>change.dob2_prev:
            self.write(cr, uid, ids, {'text23': 'Update'}, context=context)
        if change.emerg_per_relation<>change.emerg_per_relation_prev:
            self.write(cr, uid, ids, {'text24': 'Update'}, context=context)
        if change.emerg_pin<>change.emerg_pin_prev:
            self.write(cr, uid, ids, {'text25': 'Update'}, context=context)
        if change.spouse_name<>change.spouse_name_prev:
            self.write(cr, uid, ids, {'text26': 'Update'}, context=context)
        url="http://ids-erp.idsil.loc:8069/web"
        if change.mobile_no<>change.mobile_no_prev or change.local_address<>change.local_address_prev:
            
            values = {
            'subject': 'Employee Information Change Request',
            'body_html': change.employee_id.display_name + ' ' + 'created change request for Mobile No./Local Address.<br/> Please take necessary action.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/><br/>Url:'+url,
            'email_to': change.employee_id.division.hr_email,
            'email_cc': change.employee_id.parent_id.work_email,
            'email_from': '*****@*****.**',
            }
        
        else:
            values = {
            'subject': 'Employee Information Change Request',
            'body_html': change.employee_id.display_name + ' ' + 'created change request . <br/>Please take necessary action.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/><br/>Url:'+url,
            'email_to': change.employee_id.division.hr_email,
            'email_from': '*****@*****.**',
              }
        
        
            
        #---------------------------------------------------------------
        mail_obj = self.pool.get('mail.mail') 
        msg_id = mail_obj.create(cr, uid, values, context=context) 
        if msg_id: 
            mail_obj.send(cr, uid, [msg_id], context=context) 
            print"mail sent successfully======"
        return self.write(cr, uid, ids, {'state': 'submitted'}, context=context)
    def validate(self, cr, uid, ids, context=None):
        """Validation Process """
        change=self.browse(cr, uid, ids, context=context)
        if change.marital<>change.marital_prev:
            self.write(cr, uid, ids, {'text1': 'Updated'}, context=context)
        if change.email<>change.email_prev:
            self.write(cr, uid, ids, {'text2': 'Updated'}, context=context)
        if change.mobile_no<>change.mobile_no_prev:
            self.write(cr, uid, ids, {'text3': 'Updated'}, context=context)
        if change.local_address<>change.local_address_prev:
            self.write(cr, uid, ids, {'text4': 'Updated'}, context=context)
        if change.permanent_address<>change.permanent_address_prev:
            self.write(cr, uid, ids, {'text5': 'Updated'}, context=context)
        if change.weight<>change.weight_prev:
            self.write(cr, uid, ids, {'text6': 'Updated'}, context=context)
        if change.passport_no<>change.passport_no_prev:
            self.write(cr, uid, ids, {'text7': 'Updated'}, context=context)
        if change.vehicle<>change.vehicle_prev:
            self.write(cr, uid, ids, {'text8': 'Updated'}, context=context)
        if change.child_name1<>change.child_name1_prev:
            self.write(cr, uid, ids, {'text9': 'Updated'}, context=context)
        if change.child_name2<>change.child_name2_prev:
            self.write(cr, uid, ids, {'text10': 'Updated'}, context=context)
        if change.emerg_per_name<>change.emerg_per_name_prev:
            self.write(cr, uid, ids, {'text11': 'Updated'}, context=context)
        if change.emerg_address<>change.emerg_address_prev:
            self.write(cr, uid, ids, {'text12': 'Updated'}, context=context)
        if change.emerg_contact_no<>change.emerg_contact_no_prev:
            self.write(cr, uid, ids, {'text13': 'Updated'}, context=context)
        if change.doa<>change.doa_prev:
            self.write(cr, uid, ids, {'text14': 'Updated'}, context=context)
        if change.blood_groups<>change.blood_groups_prev:
            self.write(cr, uid, ids, {'text15': 'Updated'}, context=context)
        if change.home_phone<>change.home_phone_prev:
            self.write(cr, uid, ids, {'text16': 'Updated'}, context=context)
        if change.pin_local<>change.pin_local_prev:
            self.write(cr, uid, ids, {'text17': 'Updated'}, context=context)
        if change.pin_permanent<>change.pin_permanent_prev:
            self.write(cr, uid, ids, {'text18': 'Updated'}, context=context)
        if change.height<>change.height_prev:
            self.write(cr, uid, ids, {'text19': 'Updated'}, context=context)
        if change.passport_till<>change.passport_till_prev:
            self.write(cr, uid, ids, {'text20': 'Updated'}, context=context)
        if change.hobby<>change.hobby_prev:
            self.write(cr, uid, ids, {'text21': 'Updated'}, context=context)
        if change.dob1<>change.dob1_prev:
            self.write(cr, uid, ids, {'text22': 'Updated'}, context=context)
        if change.dob2<>change.dob2_prev:
            self.write(cr, uid, ids, {'text23': 'Updated'}, context=context)
        if change.emerg_per_relation<>change.emerg_per_relation_prev:
            self.write(cr, uid, ids, {'text24': 'Updated'}, context=context)
        if change.emerg_pin<>change.emerg_pin_prev:
            self.write(cr, uid, ids, {'text25': 'Updated'}, context=context)
        if change.spouse_name<>change.spouse_name_prev:
            self.write(cr, uid, ids, {'text26': 'Updated'}, context=context)
        email=change.employee_id.work_email
        emp_obj=self.pool.get('hr.employee')
        emp_id=emp_obj.search(cr, uid, [('id','=',change.employee_id.id)])
        emp_data = emp_obj.browse(cr, uid, emp_id)
        if emp_data:
            emp_obj.write(cr, uid, emp_data.id, {
                                         'marital': change.marital,
                                         'marriage_date': change.doa,
                                         'work_email': change.email,
                                         'blood_groups': change.blood_groups,
                                         'mobile_phone': change.mobile_no,
                                         'work_phone': change.home_phone,
                                         'permanent_address': change.permanent_address,
                                         'weight': change.weight,
                                         'height': change.height,
                                         'passport_id': change.passport_no,
                                         'current_address': change.local_address,}, context=context)
        url="http://ids-erp.idsil.loc:8069/web"
        if change.mobile_no<>change.mobile_no_prev or change.local_address<>change.local_address_prev:
            values = {
            'subject': 'Employee Information Change Request',
            'body_html': 'Your change request for Mobile No./Local Address is approved.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/><br/>Url:'+url,
            'email_to': email,
            'email_cc': change.employee_id.parent_id.work_email,
            'email_from': '*****@*****.**',
            }
        else:
            values = {
            'subject': 'Information Change Request Status',
            'body_html': 'Your change request is approved.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/><br/>Url:'+url,
            'email_to': email,
            'email_from': '*****@*****.**',
              }
        
        #---------------------------------------------------------------
        mail_obj = self.pool.get('mail.mail') 
        msg_id = mail_obj.create(cr, uid, values, context=context) 
        if msg_id: 
            mail_obj.send(cr, uid, [msg_id], context=context)
        date = time.strftime("%Y-%m-%d"), 
        return self.write(cr, uid, ids, {'state': 'validated','date': date}, context=context)
    def refuse(self, cr, uid, ids, context=None):
        """In case, Form get refused. """
        change=self.browse(cr, uid, ids, context=context)
        if change.marital<>change.marital_prev:
            self.write(cr, uid, ids, {'text1': 'Not Updated'}, context=context)
        if change.email<>change.email_prev:
            self.write(cr, uid, ids, {'text2': 'Not Updated'}, context=context)
        if change.mobile_no<>change.mobile_no_prev:
            self.write(cr, uid, ids, {'text3': 'Not Updated'}, context=context)
        if change.local_address<>change.local_address_prev:
            self.write(cr, uid, ids, {'text4': 'Not Updated'}, context=context)
        if change.permanent_address<>change.permanent_address_prev:
            self.write(cr, uid, ids, {'text5': 'Not Updated'}, context=context)
        if change.weight<>change.weight_prev:
            self.write(cr, uid, ids, {'text6': 'Not Updated'}, context=context)
        if change.passport_no<>change.passport_no_prev:
            self.write(cr, uid, ids, {'text7': 'Not Updated'}, context=context)
        if change.vehicle<>change.vehicle_prev:
            self.write(cr, uid, ids, {'text8': 'Not Updated'}, context=context)
        if change.child_name1<>change.child_name1_prev:
            self.write(cr, uid, ids, {'text9': 'Not Updated'}, context=context)
        if change.child_name2<>change.child_name2_prev:
            self.write(cr, uid, ids, {'text10': 'Not Updated'}, context=context)
        if change.emerg_per_name<>change.emerg_per_name_prev:
            self.write(cr, uid, ids, {'text11': 'Not Updated'}, context=context)
        if change.emerg_address<>change.emerg_address_prev:
            self.write(cr, uid, ids, {'text12': 'Not Updated'}, context=context)
        if change.emerg_contact_no<>change.emerg_contact_no_prev:
            self.write(cr, uid, ids, {'text13': 'Not Updated'}, context=context)
        if change.doa<>change.doa_prev:
            self.write(cr, uid, ids, {'text14': 'Not Updated'}, context=context)
        if change.blood_group<>change.blood_group_prev:
            self.write(cr, uid, ids, {'text15': 'Not Updated'}, context=context)
        if change.home_phone<>change.home_phone_prev:
            self.write(cr, uid, ids, {'text16': 'Not Updated'}, context=context)
        if change.pin_local<>change.pin_local_prev:
            self.write(cr, uid, ids, {'text17': 'Not Updated'}, context=context)
        if change.pin_permanent<>change.pin_permanent_prev:
            self.write(cr, uid, ids, {'text18': 'Not Updated'}, context=context)
        if change.height<>change.height_prev:
            self.write(cr, uid, ids, {'text19': 'Not Updated'}, context=context)
        if change.passport_till<>change.passport_till_prev:
            self.write(cr, uid, ids, {'text20': 'Not Updated'}, context=context)
        if change.hobby<>change.hobby_prev:
            self.write(cr, uid, ids, {'text21': 'Not Updated'}, context=context)
        if change.dob1<>change.dob1_prev:
            self.write(cr, uid, ids, {'text22': 'Not Updated'}, context=context)
        if change.dob2<>change.dob2_prev:
            self.write(cr, uid, ids, {'text23': 'Not Updated'}, context=context)
        if change.emerg_per_relation<>change.emerg_per_relation_prev:
            self.write(cr, uid, ids, {'text24': 'Not Updated'}, context=context)
        if change.emerg_pin<>change.emerg_pin_prev:
            self.write(cr, uid, ids, {'text25': 'Not Updated'}, context=context)
        if change.spouse_name<>change.spouse_name_prev:
            self.write(cr, uid, ids, {'text26': 'Not Updated'}, context=context)
        email=change.employee_id.work_email
        url="http://ids-erp.idsil.loc:8069/web"
        if change.mobile_no<>change.mobile_no_prev or change.local_address<>change.local_address_prev:
            values = {
            'subject': 'Employee Information Change Request',
            'body_html': 'Your change request for Mobile No./Local Address is refused . <br/>Please Contact to your HR department.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/><br/>Url:'+url,
            'email_to': email,
            'email_cc': change.employee_id.parent_id.work_email,
            'email_from': '*****@*****.**',
            }
        else:
            values = {
            'subject': 'Information Change Request Status',
            'body_html': 'Your change request is refused .<br/> Please Contact to your HR department.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/><br/>Url:'+url,
            'email_to': email,
            'email_from': '*****@*****.**',
              }
        
        
        #---------------------------------------------------------------
        mail_obj = self.pool.get('mail.mail') 
        msg_id = mail_obj.create(cr, uid, values, context=context) 
        if msg_id: 
            mail_obj.send(cr, uid, [msg_id], context=context)
        date = time.strftime("%Y-%m-%d"), 
        return self.write(cr, uid, ids, {'state': 'refused','date': date}, context=context)
class session (osv.Model):
    _name = 'openacademy.session'
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    
    def compute_available_seats(self, seats, attendee_ids):
        if seats == 0 or len(attendee_ids) > seats:
            return 0.0
        else:
            return 100.0 - (float(len(attendee_ids)) / seats * 100)
    
    def get_available_seats(self, cr, uid, ids, field, arg, context={}):
        res = {}
        sessions = self.browse(cr, uid, ids, context=context)
        for session in sessions:
            res[session.id] = self.compute_available_seats(session.seats, session.attendee_ids)
        return res
    
    def onchange_seats(self, cr, uid, ids, seats, attendee_ids, context={}):
        res = {
            'value': {
                'available_seats': self.compute_available_seats(seats, attendee_ids)
                }
        }
        if seats < 0:
            res['warning'] = {
                'title':    _('Warning: wrong value'),
                'message':  _('The seats number cannot be negative.')
            }
        elif seats < len(attendee_ids):
            res['warning'] = {
                'title':    _('Warning: wrong value'),
                'message':  _('There is not enough seats for everyone.')
            }
        return res
    
    def _compute_end_date(self, cr, uid, ids, fields, arg, context={}):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            if session.start_date and session.duration:
                start_date = datetime.strptime(session.start_date, "%Y-%m-%d")
                duration = timedelta(days=(session.duration-1))
                end_date = start_date + duration
                res[session.id] = end_date.strftime('%Y-%m-%d')
            else:
                res[session.id] = session.start_date
        return res
    
    def _set_end_date(self, cr, uid, id, field, value, arg, context={}):
        session = self.browse(cr, uid, id, context=context)
        if session.start_date and value:
            start_date = datetime.strptime(session.start_date, "%Y-%m-%d")
            end_date = datetime.strptime(value[:10], "%Y-%m-%d")
            duration = end_date - start_date
            self.write(cr, uid, id, {'duration': (duration.days + 1)}, context=context)
    
    def _compute_hours(self, cr, uid, ids, fields, arg, context={}):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            res[session.id] = (session.duration * 24 if session.duration else 0)
            """
            if session.duration:
                res[session.id] = session.duration * 24
            else:
                res[session.id] = 0
                """
        return res
    
    def _compute_attendee_count(self, cr, uid, ids, fields, arg, context={}):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            res[session.id] = len(session.attendee_ids)
        return res
    
    def _set_hours(self, cr, uid, id, field, value, arg, context={}):
        if value:
            self.write(cr, uid, id, {'duration':(value/24)}, context=context)
    
    def action_draft(self, cr, uid, ids, context={}):
        return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
        
    def action_confirmed(self, cr, uid, ids, context={}):
        return self.write(cr, uid, ids, {'state': 'confirmed'}, context=context)
        
    def action_done(self, cr, uid, ids, context={}):
        return self.write(cr, uid, ids, {'state': 'done'}, context=context)
    
    _columns = {
        'name':         fields.char(string="Name", size=128, required=True, translate=True),
        'start_date':   fields.date(string="Start date"),
        'duration':     fields.float(string="Duration", digits=(6,2), help="Session durantion in days"),
        'seats':        fields.integer(string="Number of seats"),
        'instructor_id':fields.many2one('res.partner', string="Instructor", ondelete="set null",
                                        domain="['|',('instructor','=',True),('category_id.name','in',['Teacher level 1', 'Teacher level 2'])]"),
        'course_id':    fields.many2one('openacademy.course', string="Course", ondelete="cascade"),
        'attendee_ids': fields.one2many('openacademy.attendee', 'session_id', string="Attendees"),
        'available_seats':  fields.function(get_available_seats, type="float", string="Available Seats (%)", readonly=True),
        'active':       fields.boolean(string="Active", help="Uncheck this to deactivate this session. Beware, it will not appear anymore in the session list."),
        'end_date':     fields.function(_compute_end_date, fnct_inv=_set_end_date, type="date", string="End date"),
        'hours':        fields.function(_compute_hours, fnct_inv=_set_hours, type="float", string="Hours"),
        'attendee_count':   fields.function(_compute_attendee_count, type="integer", string="Attendee Count", store=True),
        'color':        fields.integer('Color'),
        'state':        fields.selection([('draft','Draft'),('confirmed','Confirmed'),('done','Done')], string="State"),
    }
    
    _defaults = {
        'start_date':   fields.date.today,
        'active':       True,
        'state':        'draft',
    }
    
    def _check_instructor_not_in_attendees(self, cr, uid, ids, context={}):
        for session in self.browse(cr, uid, ids, context=context):
            #partners = []
            #for attendee in session.attendee_ids:
            #    partners.append(attendee.partner_id)
            partners = [attendee.partner_id for attendee in session.attendee_ids]
            if session.instructor_id and session.instructor_id in partners:
                return False
        return True
    
    _constraints = [
        (_check_instructor_not_in_attendees,
        "The instructor cannot be also an attendee.",
        ['instructor_id', 'attendee_ids'])
    ]
Example #11
0
class sale_order(orm.Model):
    _inherit = "sale.order"

    def default_get(self, cr, uid, fields, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        # sale_order_obj = self.pool['sale.order']
        # sale_order_line_obj = self.pool['sale.order.line']
        res = super(sale_order, self).default_get(cr, uid, fields, context=context)
        if not res.get('shop_id', False):
            shop_ids = self.pool['sale.order'].search(cr, uid, [], limit=1, context=context)
            if shop_ids:
                res['shop_id'] = shop_ids[0]
        if not res.get('section_id', False):
            section_ids = self.pool['crm.case.section'].search(cr, uid, [('user_id', '=', uid)], context=context)
            if section_ids:
                res['section_id'] = section_ids[0]
        return res

    def service_only(self, cr, uid, ids, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        service = True
        if not isinstance(ids, (list, tuple)):
            ids = [ids]

        for order in self.browse(cr, uid, ids, context):
            if order.order_line:
                for order_line in order.order_line:
                    if order_line.product_id and order_line.product_id.type != 'service':
                        return False
            elif not service:
                    return False
        return True

    def hook_sale_state(self, cr, uid, orders, vals, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        # function call if change state the sale order
        return True

    def adaptative_function(self, cr, uid, ids, vals, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if not isinstance(ids, (list, tuple)):
            ids = [ids]
        if vals.get('section_id', False) or vals.get('carrier_id', False) or vals.get('payment_term'):
            for order in self.browse(cr, uid, ids, context):
                partner_vals = {}
                if not order.partner_id.section_id:
                    partner_vals['section_id'] = vals.get('section_id')
                if not order.partner_id.property_delivery_carrier:
                    partner_vals['property_delivery_carrier'] = vals.get('carrier_id')
                if not order.partner_id.property_payment_term:
                    partner_vals['property_payment_term'] = vals.get('payment_term')
                if partner_vals:
                    self.pool['res.partner'].write(cr, uid, [order.partner_id.id], partner_vals, context)
        return True

    def create(self, cr, uid, vals, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        ids = super(sale_order, self).create(cr, uid, vals, context=context)
        self.adaptative_function(cr, uid, ids, vals, context)
        return ids

    def write(self, cr, uid, ids, vals, context=None):
        if context is None:
            context = self.pool['res.users'].context_get(cr, uid)

        if not isinstance(ids, (list, tuple)):
            ids = [ids]

        orders = self.browse(cr, uid, ids, context)

        self.adaptative_function(cr, uid, ids, vals, context)
        if vals.get('state', False):
            self.hook_sale_state(cr, uid, orders, vals, context)

        return super(sale_order, self).write(cr, uid, ids, vals, context=context)

    def action_wait(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)

        for order in self.browse(cr, uid, ids, context):
            company = self.pool['res.users'].browse(cr, uid, uid).company_id

            if self.service_only(cr, uid, [order.id], context) and order.order_policy and order.order_policy == 'picking':
                if company.auto_order_policy:
                    order.write({'order_policy': 'manual'})
                else:
                    raise orm.except_orm(_('Warning'), _(
                        "You can't create an order with Invoicing being based on Picking if there are only service products"))
            else:
                if company.auto_order_policy:
                    default = self.default_get(cr, uid, ['order_policy'], context)
                    order.write({'order_policy': default.get('order_policy')})

        return super(sale_order, self).action_wait(cr, uid, ids, context)

    def copy(self, cr, uid, ids, default, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        default.update(
            {
                'tech_validation': False,
                'manager_validation': False,
                'customer_validation': False,
                'email_sent_validation': False,
                'supervisor_validation': False,
                'date_order': fields.date.context_today,
            }
        )
        default.update(self.default_get(cr, uid, ['order_policy', 'picking_policy', 'invoice_quantity'], context))
        return super(sale_order, self).copy(cr, uid, ids, default, context)

    def action_cancel_draft(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {
                'tech_validation': False,
                'manager_validation': False,
                'customer_validation': False,
                'email_sent_validation': False,
                'supervisor_validation': False,
        })
        super(sale_order, self).action_cancel_draft(cr, uid, ids, *args)
        return True

    def onchange_invoice_type_id(self, cr, uid, ids, invoice_type_id, context=None):
        if context is None:
            context = self.pool['res.users'].context_get(cr, uid)
        res = {}
        if invoice_type_id:
            invoice_type_obj = self.pool['sale_journal.invoice.type']
            invoice_type = invoice_type_obj.browse(cr, uid, invoice_type_id, context)
            if invoice_type.invoicing_method == 'grouped':
                res['order_policy'] = 'picking'
        return {'value': res}

    def onchange_partner_id(self, cr, uid, ids, part, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        res = super(sale_order, self).onchange_partner_id(cr, uid, ids, part)
        if res.get('value', False) and part:
            if not res['value'].get('fiscal_position', False):
                company_id = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.id
                company = self.pool['res.company'].browse(cr, uid, company_id, context)
                if company.default_property_account_position:
                    res['value']['fiscal_position'] = company.default_property_account_position and company.default_property_account_position.id
        return res

    def _credit_limit(self, cr, uid, ids, field_name, arg, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        res = dict.fromkeys(ids, 0.0)
        for order in self.browse(cr, uid, ids, context=context):

            if order.order_policy == 'prepaid':
                res[order.id] = 0
                continue
            partner = order.partner_id
            credit = partner.credit
            # We sum from all the sale orders that are aproved, the sale order lines that are not yet invoiced
            order_obj = self.pool['sale.order']
            approved_invoices_ids = order_obj.search(cr, uid, [('partner_id', '=', partner.id), ('state', 'not in', ['draft', 'cancel', 'done'])], context=context)
            approved_invoices_amount = 0.0
            for orders in order_obj.browse(cr, uid, approved_invoices_ids, context=context):
                for order_line in orders.order_line:
                    if not order_line.invoiced:
                        approved_invoices_amount += order_line.price_subtotal

            # We sum from all the invoices that are in draft the total amount
            invoice_obj = self.pool['account.invoice']
            draft_invoices_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner.id), ('state', '=', 'draft')], context=context)
            draft_invoices_amount = 0.0
            for invoice in invoice_obj.browse(cr, uid, draft_invoices_ids, context=context):
                draft_invoices_amount += invoice.amount_total
            available_credit = partner.credit_limit - credit - approved_invoices_amount - draft_invoices_amount
            res[order.id] = available_credit - order.amount_total
        return res

    def partner_overdue_check(self, cr, uid, company, partner, context):
        # return True if there are same overdue payment
        account_move_line_obj = self.pool['account.move.line']
        overdue_date = (datetime.today() - relativedelta(days=company.date_max_overdue or 0.0)).strftime(DEFAULT_SERVER_DATE_FORMAT)

        account_move_ids = account_move_line_obj.search(cr, uid, [
            ('partner_id', '=', partner.id),
            ('account_id.type', 'in', ['receivable', 'payable']),
            ('stored_invoice_id', '!=', False),
            ('reconcile_id', '=', False),
            ('date_maturity', '<', overdue_date)], context=context)

        if account_move_ids:
            return True

        return False

    def check_limit(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context=context):
            if order.credit_limit < 0 and order.company_id and order.company_id.check_credit_limit:
                title = _(u'Credit Over Limit')
                msg = _(u'Is not possible to confirm because customer exceed the credit limit. \n Is Possible change the Order Policy \"Pay Before Delivery\" \n on tab \"Other Information\"')
                raise orm.except_orm(_(title), _(msg))
                return False

            if order.visible_minimum and order.sale_order_minimun > order.amount_untaxed:
                if order.shop_id.user_allow_minimun_id and order.shop_id.user_allow_minimun_id.id == uid:  # if user can validate
                    return True
                # test if on line there are the product
                if order.shop_id.product_allow_minimun_id:
                    for line in order.order_line:
                        if line.product_id and line.product_id == order.shop_id.product_allow_minimun_id:
                            return True

                title = _(u'Minimum Amount Billable')
                if order.shop_id.user_allow_minimun_id:
                    msg = _(u'Is not possible to confirm because is not reached the minimum billable {amount} {currency} \n Only {user} can do it').format(amount=order.sale_order_minimun, currency=order.pricelist_id.currency_id.symbol, user=order.shop_id.user_allow_minimun_id.name)
                else:
                    msg = _(u'Is not possible to confirm because is not reached the minimum billable {amount} {currency}').format(amount=order.sale_order_minimun, currency=order.pricelist_id.currency_id.symbol)

                if order.shop_id.product_allow_minimun_id:
                    msg += _(u'\n\n or add the product \'{product}\'').format(product=order.shop_id.product_allow_minimun_id.name_get()[0][1])

                raise orm.except_orm(_(title), _(msg))
                return False

            if order.company_id and order.company_id.check_overdue:
                if self.partner_overdue_check(cr, uid, order.company_id, order.partner_id, context):
                    title = _(u'Overdue Limit')
                    msg = _(u'Is not possible to confirm because customer have a overdue payment')
                    raise orm.except_orm(_(title), _(msg))
                return False
        return True

    def name_get(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if not len(ids):
            return []
        res = []
        for sale in self.browse(cr, uid, ids, context=context):
            name = u'[{sale_name}] {partner_name}'.format(sale_name=sale.name, partner_name=sale.partner_id.name)
            res.append((sale.id, name))
        return res

    def name_search(self, cr, uid, name='', args=None, operator='ilike', context=None, limit=10):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if not args:
            args = []
        if name:
            ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context)
            if not len(ids):
                ids = self.search(cr, uid, [('partner_id', 'ilike', name)] + args, limit=limit, context=context)
                ids = list(set(ids))
            if not len(ids):
                ptrn = re.compile('(\[(.*?)\])')
                res = ptrn.search(name)
                if res:
                    ids = self.search(
                        cr, uid, [('name', '=', res.group(2))] + args, limit=limit, context=context)
        else:
            ids = self.search(cr, uid, args, limit=limit, context=context)

        result = self.name_get(cr, uid, ids, context=context)
        return result

    def __init__(self, registry, cr):
        """
            Add state "Suspended"
        """
        super(sale_order, self).__init__(registry, cr)
        options = [('wait_technical_validation', _('Technical Validation')),
                   ('wait_manager_validation', _('Manager Validation')),
                   ('send_to_customer', _('Send To Customer')),
                   ('wait_customer_validation', _('Customer Validation')),
                   ('wait_supervisor_validation', _('Supervisor Validation'))]

        type_selection = self._columns['state'].selection
        for option in options:
            if option not in type_selection:
                type_selection.append(option)

    def _get_shop_id(self, cr, uid, context):
        shop_ids = self.pool['sale.shop'].search(cr, uid, [], context=context, limit=1)
        return shop_ids and shop_ids[0] or False

    _columns = {
        'create_uid': fields.many2one('res.users', 'Created by', readonly=True),
        'credit_limit': fields.function(_credit_limit, string="Remaining Credit Limit", type='float', readonly=True, method=True),
        'sale_order_minimun': fields.related('shop_id', 'sale_order_minimun', type='float', string='Minimun Invoice', store=False, readonly=True),
        'visible_minimum': fields.related('shop_id', 'sale_order_have_minimum', type='boolean', string=_('Minimun Amount'), store=False, readonly=True),
        'visible_credit_limit': fields.related('company_id', 'check_credit_limit', type='boolean', string=_('Fido Residuo Visibile'), store=False, readonly=True),
        'validity': fields.date('Validity'),
        'order_line': fields.one2many('sale.order.line', 'order_id', 'Order Lines', readonly=True, states={
            'draft': [('readonly', False)],
            'wait_technical_validation': [('readonly', False)],
            'wait_manager_validation': [('readonly', False)]}
        ),
        'project_id': fields.many2one('account.analytic.account', 'Contract/Analytic Account', readonly=True, states={
            'draft': [('readonly', False)],
            'wait_technical_validation': [('readonly', False)],
            'wait_manager_validation': [('readonly', False)],
            'send_to_customer': [('readonly', False)],
            'wait_customer_validation': [('readonly', False)],
        }, help="The analytic account related to a sales order."),
        'required_tech_validation': fields.related('company_id', 'need_tech_validation', type='boolean', string=_('Required Technical Validation'), store=False, readonly=True),
        'need_tech_validation': fields.boolean("Technical Validation", readonly=True),
        'tech_validation': fields.boolean("Tech Validated ?", readonly=True),
        'required_manager_validation': fields.related('company_id', 'need_manager_validation', type='boolean', string=_('Required Manager Validation'), store=False, readonly=True),
        'need_manager_validation': fields.boolean("Manager Validation", readonly=True),
        'manager_validation': fields.boolean("Manager Validated ?", readonly=True),
        'email_sent_validation': fields.boolean("Email Sent to Customer ?", readonly=True),
        'customer_validation': fields.boolean("Customer Validated ?", readonly=True),
        # A validation after customer confirmation:
        'required_supervisor_validation': fields.related('company_id', 'need_supervisor_validation', type='boolean', string=_('Required Supervisor Validation'), store=False, readonly=True),
        'skip_supervisor_validation_onstandard_product': fields.related('company_id', 'skip_supervisor_validation_onstandard_product',
                                                                        type='boolean',
                                                                        string=_(
                                                                            'Skip Supervisor Verification if there are only standard product'),
                                                                        store=False,
                                                                        readonly=True),
        'supervisor_validation': fields.boolean(_("Supervisor Validated?"), readonly=True),
        'product_id': fields.related('order_line', 'product_id', type='many2one', relation='product.product', string='Product'),
        'revision_note': fields.char('Reason', size=256, select=True),
        'lost_reason_id': fields.many2one('crm.lost.reason', string='Lost Reason'),
        'last_revision_note': fields.related('sale_version_id', 'revision_note', type='char', string="Last Revision Note", store=True),
    }

    _defaults = {
        'need_tech_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_tech_validation,
        'need_manager_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_manager_validation,
        'skip_supervisor_validation_onstandard_product': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.skip_supervisor_validation_onstandard_product,
        'required_tech_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_tech_validation,
        'required_manager_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_manager_validation,
        'required_supervisor_validation': lambda self, cr, uid, context: self.pool['res.users'].browse(cr, uid, uid, context).company_id.need_supervisor_validation,
        'validity': lambda self, cr, uid, context: (datetime.today() + relativedelta(days=self.pool['res.users'].browse(cr, uid, uid, context).company_id.default_sale_order_validity or 0.0)).strftime(DEFAULT_SERVER_DATE_FORMAT),
        'shop_id': lambda self, cr, uid, context: self._get_shop_id(cr, uid, context),
    }

    def action_reopen(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        result = super(sale_order, self).action_reopen(cr, uid, ids, context=context)

        for order in self.browse(cr, uid, ids, context):
            if order.state == 'draft':
                self.write(cr, uid, ids, {
                    'tech_validation': False,
                    'manager_validation': False,
                    'email_sent_validation': False,
                    'customer_validation': False,
                }, context)
        return result

    def check_direct_order_confirm(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if order.state == 'draft' and order.pricelist_id and order.pricelist_id.contract:
                return True
            else:
                return False

    def check_tech_validation(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if order.shop_id.user_tech_validation_id:
                if order.shop_id.user_tech_validation_id.id == uid:
                    return True
                else:
                    title = _('Technical Validation')
                    msg = _(u"It's not possible to confirm, for shop {shop} only user '{user}' can do it".format(shop=order.shop_id.name, user=order.shop_id.user_tech_validation_id.name))
                    raise orm.except_orm(_(title), _(msg))
                    return False

            else:
                return True

    def check_manager_validation(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if order.shop_id.user_manager_validation_id:
                if order.shop_id.user_manager_validation_id.id == uid:
                    return True
                else:
                    title = _('Manager Validation')
                    msg = _(u"It's not possible to confirm, for shop {shop} only user '{user}' can do it".format(shop=order.shop_id.name, user=order.shop_id.user_manager_validation_id.name))
                    raise orm.except_orm(_(title), _(msg))
                    return False
            else:
                return True

    def check_supervisor_validation(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if order.shop_id.user_supervisor_validation_id:
                if order.shop_id.user_supervisor_validation_id.id == uid:
                    return True
                else:
                    title = _('Supervisor Validation')
                    msg = _(u"It's not possible to confirm, for shop {shop} only user '{user}' can do it".format(shop=order.shop_id.name, user=order.shop_id.user_supervisor_validation_id.name))
                    raise orm.except_orm(_(title), _(msg))
                    return False
            else:
                return True

    def required_tech_validation(self, order):
        if order.company_id.tech_validation_if_no_product:
            for line in order.order_line:
                if not line.product_id:
                    order.write({'need_tech_validation': True})
                    return True
        return False

    def check_discount(self, order):
        if order.company_id.enable_discount_validation:
            max_discount = order.company_id.max_discount
            for line in order.order_line:
                if line.discount > max_discount:
                    order.write({'need_manager_validation': True})
                    return True
        return False

    def action_validate(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            if not order.partner_id.validate and order.company_id.enable_partner_validation:
                title = _('Partner To Validate')
                msg = _("It's not possible to confirm because customer must be validated")
                raise orm.except_orm(_(title), _(msg))
                return False

            if order.need_tech_validation and not order.tech_validation or self.required_tech_validation(order):
                vals = {
                    'state': 'wait_technical_validation',
                }
            elif self.check_discount(order):
                vals = {
                    'state': 'wait_manager_validation',
                }
            elif order.company_id.enable_margin_validation and order.amount_untaxed and (order.margin / order.amount_untaxed) * 100 < order.company_id.minimum_margin and not order.manager_validation:
                vals = {
                    'state': 'wait_manager_validation',
                }
            elif order.need_manager_validation and not order.manager_validation:
                vals = {
                    'state': 'wait_manager_validation',
                }
            elif not order.email_sent_validation:
                vals = {
                    'state': 'send_to_customer',
                }
            elif not order.customer_validation:
                vals = {
                    'state': 'wait_customer_validation',
                }
            elif order.required_supervisor_validation and not order.supervisor_validation:
                vals = {
                    'state': 'wait_supervisor_validation',
                }
            else:
                vals = {
                    'state': 'draft',
                    'tech_validation': False,
                    'manager_validation': False,
                    'customer_validation': False,
                    'email_sent_validation': False,
                    'supervisor_validation': False
                }
            order.write(vals)

        return True

    def check_validate(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        for order in self.browse(cr, uid, ids, context):
            res = True
            if order.need_tech_validation and not order.tech_validation:
                res = False
            elif order.need_manager_validation and not order.manager_validation:
                res = False
            elif order.required_supervisor_validation and not order.supervisor_validation:
                if order.skip_supervisor_validation_onstandard_product:
                    for line in order.order_line:
                        if line.product_id and line.product_id.is_kit:
                            return False
                    res = True
                else:
                    res = False
            return res and order.email_sent_validation and order.customer_validation
        return True

    def check_direct_confirm(self, cr, uid, ids, context=None):
        context = context or self.pool['res.users'].context_get(cr, uid)
        if self.check_limit(cr, uid, ids, context):
            for order in self.browse(cr, uid, ids, context):
                values = {
                    'state': 'wait_customer_validation',
                    'customer_validation': True
                }
                if order.need_tech_validation:
                    values['tech_validation'] = True

                if (order.company_id.enable_margin_validation and order.amount_untaxed and (order.margin / order.amount_untaxed) < order.company_id.minimum_margin) or order.need_manager_validation:
                    values['manager_validation'] = True

                if order.required_supervisor_validation:
                    values['supervisor_validation'] = True

                self.write(cr, uid, [order.id], values, context)

            return self.action_validate(cr, uid, ids, context)
        else:
            return False

    def copy(self, cr, uid, ids, default={}, context=None):
        default = default or {}
        context = context or self.pool['res.users'].context_get(cr, uid)
        default.update({
            'validity': (datetime.today() + relativedelta(days=self.pool['res.users'].browse(cr, uid, uid, context).company_id.default_sale_order_validity or 0.0)).strftime(DEFAULT_SERVER_DATE_FORMAT),
            'tech_validation': False,
            'manager_validation': False,
            'customer_validation': False,
            'email_sent_validation': False,
            'supervisor_validation': False,
            'lost_reason_id': False
        })
        return super(sale_order, self).copy(cr, uid, ids, default, context=context)
Example #12
0
class Message(osv.Model):
    #TODO: turn off for data import only
    _log_access = True
    _name = "message.message"
    _order = "write_date desc,sequence"
    _description = 'UPDIS Message'
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    def _default_fbbm(self, cr, uid, context=None):
        employee_ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)])
        if employee_ids:
            return self.pool.get('hr.employee').browse(cr, uid, employee_ids[0]).department_id.name

    def _default_department(self, cr, uid, context=None):
        employee_ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)])
        if employee_ids:
            return self.pool.get('hr.employee').browse(cr, uid, employee_ids[0]).department_id.id

    def _get_image(self, cr, uid, ids, name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            result[obj.id] = tools.image_get_resized_images(obj.image)
        return result

    def _set_image(self, cr, uid, id, field_name, value, args, context=None):
        return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)

    def _get_name_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            result[obj.id] = obj.is_display_name and obj.create_uid.name or u'匿名用户'
        return result

    def _get_message_meta_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            message_meta = ''
            if obj.category_id.message_meta:
                env = Env(cr, uid, 'message.message', [obj.id])
                message_meta = eval(obj.category_id.message_meta, env, nocopy=True)
            result[obj.id] = message_meta
        return result

    def _get_category_message_title_meta_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            category_message_title_meta = ''
            if obj.category_id.category_message_title_meta:
                env = Env(cr, uid, 'message.message', [obj.id])
                category_message_title_meta = eval(obj.category_id.category_message_title_meta, env, nocopy=True)
            result[obj.id] = category_message_title_meta
        return result


    def _get_create_date_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):

            if obj.create_date:
                create_date_display = datetime.datetime.strptime(obj.create_date,
                                                                 '%Y-%m-%d %H:%M:%S') + datetime.timedelta(hours=8)
                result[obj.id] = create_date_display.strftime('%Y-%m-%d %H:%M:%S')
        return result

    def _get_write_date_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):

            if obj.write_date:
                write_date_display = datetime.datetime.strptime(obj.write_date,
                                                                '%Y-%m-%d %H:%M:%S') + datetime.timedelta(hours=8)
                result[obj.id] = write_date_display.strftime('%Y-%m-%d %H:%M:%S')
        return result

    def _get_shorten_name(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            size = obj.category_id.category_message_title_size
            title = len(obj.name) > size and obj.name[:size] + '...' or obj.name
            result[obj.id] = title
        return result

    def _get_message_list_meta_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            message_meta = ''
            if obj.category_id.message_meta:
                env = Env(cr, uid, 'message.message', [obj.id])
                message_meta = eval(obj.category_id.phone_message_list_meta, env, nocopy=True)
            result[obj.id] = message_meta
        return result

    def _get_message_detail_meta_display(self, cr, uid, ids, field_name, args, context=None):
        result = dict.fromkeys(ids, False)
        for obj in self.browse(cr, uid, ids, context=context):
            category_message_title_meta = ''
            if obj.category_id.category_message_title_meta:
                env = Env(cr, uid, 'message.message', [obj.id])
                category_message_title_meta = eval(obj.category_id.phone_message_detail_meta, env, nocopy=True)
            result[obj.id] = category_message_title_meta
        return result

    def _get_vote_count(self, cr, uid, ids, field_name, args, context=None):
        """
            Either way, it must return a dictionary of values of the form
            {'id_1_': 'value_1_', 'id_2_': 'value_2_',...}.

            If multi is set, then field_name is replaced by field_names:
            a list of the field names that should be calculated.
            Each value in the returned dictionary is also a dictionary from field name to value.
            For example, if the fields 'name', and 'age' are both based on the vital_statistics function,
            then the return value of vital_statistics might look like this when ids is [1, 2, 5]:
            {
                1: {'name': 'Bob', 'age': 23},
                2: {'name': 'Sally', 'age', 19},
                5: {'name': 'Ed', 'age': 62}
            }
        """
        result = dict.fromkeys(ids, False)
        message_vote_obj = self.pool.get('message.vote')
        for message in self.browse(cr, uid, ids, context=context):
            vote_like_count = len(message_vote_obj.search(cr, SUPERUSER_ID, [('message_id', '=', message.id), ('up', '=', True)], context))
            vote_unlike_count = len(message_vote_obj.search(cr, SUPERUSER_ID, [('message_id', '=', message.id), ('up', '=', False)], context))
            result[message.id] = {
                'vote_like': vote_like_count,
                'vote_unlike': vote_unlike_count,
            }
        return result

    _columns = {
        'name': fields.char("Title", size=128, required=True),
        'shorten_name': fields.function(_get_shorten_name, type="char", size=256, string="Shorten title"),
        'message_meta_display': fields.function(_get_message_meta_display, type="char", size=256, string="Meta"),
        'category_message_title_meta_display': fields.function(_get_category_message_title_meta_display, type="char",
                                                               size=256, string="Category meta"),


        'message_list_meta_display': fields.function(_get_message_list_meta_display, type="char", size=256,
                                                     string="Phone Message List Meta"),
        'message_detail_meta_display': fields.function(_get_message_detail_meta_display, type="char",
                                                       size=256, string="Phone Message Detail meta"),
        'category_id': fields.many2one('message.category', 'Category', required=True, change_default=True),
        'content': fields.text("Content"),
        'sequence': fields.integer("Display Sequence"),
        'is_display_name': fields.boolean('Display name?'),
        'fbbm': fields.char('Publisher', size=128),
        'read_times': fields.integer("Read Times"),
        'expire_date': fields.date('Expire Date'),
        'create_date': fields.datetime('Created on', select=True ,readonly=True),
        'department_id': fields.many2one("hr.department", "Department", domain=[('deleted', '=', False)]),
        'create_uid': fields.many2one('res.users', 'Author', select=True, readonly=True),
        'write_date': fields.datetime('Modification date', select=True , readonly=True),
        'write_uid': fields.many2one('res.users', 'Last Contributor', select=True , readonly=True),
        'source': fields.char("Message Source", size=128),
        'name_for_display': fields.function(_get_name_display, type="char", size=64, string="Name"),
        'sms_receiver_ids': fields.many2many("hr.employee", "message_hr_employee_rel", "message_id", "hr_employee_id",
                                             "SMS Receiver"),
        'sms': fields.text('SMS', size=140),
        'is_allow_send_sms': fields.related('category_id', 'is_allow_send_sms', type="boolean",
                                            string="Allow send SMS?"),
        'is_allow_sms_receiver': fields.related('category_id', 'is_allow_send_sms', type="boolean",
                                                string="Allow specify sms receiver?"),
        'category_id_name': fields.related('category_id', 'name', type="char",
                                           string="category name"),
        'category_id_is_anonymous_allowed': fields.related('category_id', 'is_anonymous_allowed', type="boolean",
                                                           string="category is anonymous allowed"),
        'category_id_is_allowed_edit_sms_text': fields.related('category_id', 'is_allowed_edit_sms_text',
                                                               type="boolean",
                                                               string="category is allowed edit sms text"),
        'create_date_display': fields.function(_get_create_date_display, type="datetime", string="Create Date Display",
                                               readonly=True),
        'write_date_display': fields.function(_get_write_date_display, type="datetime", string="Write Date Display",
                                              readonly=True),
        'vote_user_ids': fields.many2many('res.users', 'message_vote', 'message_id', 'user_id', string='Votes',
                                          help='Users that voted for this message'),
        'vote_like': fields.function(_get_vote_count, type="integer", string='Like', multi='vote'),
        'vote_unlike': fields.function(_get_vote_count, type='integer', string='Unlike', multi='vote'),
    }
    _defaults = {
        'fbbm': _default_fbbm,
        'department_id': _default_department,
        'is_display_name': True,
    }

    def onchange_category(self, cr, uid, ids, category_id, context=None):
        ret = {'value': {}}
        if category_id:
            message_category = self.pool.get('message.category').browse(cr, uid, category_id)
            sms_vals = {
                'is_allow_send_sms': message_category.is_allow_send_sms,
                'is_allow_sms_receiver': message_category.is_allow_sms_receiver,
                'sms_receiver_ids': [x.id for x in message_category.default_sms_receiver_ids],
                'category_id_name': message_category.name,
                'category_id_is_anonymous_allowed': message_category.is_anonymous_allowed,
                'category_id_is_allowed_edit_sms_text': message_category.is_allowed_edit_sms_text,
            }
            ret['value'].update(sms_vals)
        return ret

    #abandon
    def onchange_name(self, cr, uid, ids, name, sms, context=None):
        ret = {'value': {}}
        if not sms:
            name_vals = {
                'sms': name,
            }
            if not len(ids):
                ret['value'].update(name_vals)
        return ret

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {'mail_create_nolog': True}
        else:
            context.update({'mail_create_nolog': True})
        if self._log_access is True:
            if not vals['category_id_is_allowed_edit_sms_text']:
                vals['sms'] = vals['name']
            mid = super(Message, self).create(cr, uid, vals, context)
            sms = self.pool.get('sms.sms')
            message = self.pool.get('message.message').browse(cr, uid, mid, context=context)
            if message.is_allow_send_sms:
                to = ','.join(
                    [rid.mobile_phone.strip() for rid in message.sms_receiver_ids if rid.mobile_phone and rid.mobile_phone.strip()])
                if to:
                    content = message.sms and message.category_id.name + ':' + message.sms or message.category_id.name + ':' + message.name
                    sid = sms.create(cr, uid, {'to': to, 'content': content, 'model': 'message.message', 'res_id': mid},
                                     context=context)
        else:
            mid = super(Message, self).create(cr, uid, vals, context)
        return mid

    def write(self, cr, uid, ids, vals, context=None):
        #get message old position
        if self._log_access is True:
            TYPE = []
            if not (len(vals) == 1 and 'read_times' in vals.keys()):
                messages_old = self.pool.get('message.message').browse(cr, 1, ids, context=context)
                for message_old in messages_old:
                    if message_old.category_id.display_position == 'shortcut':
                        TYPE.append('0')
                    if message_old.category_id.display_position == 'content_left':
                        TYPE.append('1')
                    if message_old.category_id.display_position == 'content_right':
                        TYPE.append('2')
                TYPE = set(TYPE)

            super(Message, self).write(cr, uid, ids, vals, context=context)
            NEW_TYPE = []
            #refresh cms page
            if not (len(vals) == 1 and 'read_times' in vals.keys()):
                #get message new position
                messages = self.pool.get('message.message').browse(cr, 1, ids, context=context)
                for message in messages:
                    if message.category_id.display_position == 'shortcut':
                        NEW_TYPE.append('0')
                    if message.category_id.display_position == 'content_left':
                        NEW_TYPE.append('1')
                    if message.category_id.display_position == 'content_right':
                        NEW_TYPE.append('2')
                NEW_TYPE = set(NEW_TYPE)

                #if old and new position is different refresh both.
                for v in (TYPE | NEW_TYPE):
                    fresh_old = CMSFresh(v)
                    fresh_old.start()
        else:
            super(Message, self).write(cr, uid, ids, vals, context=context)

        return True


    def unlink(self, cr, uid, ids, context=None):
        #get old position
        TYPE = []
        messages_old = self.pool.get('message.message').browse(cr, 1, ids, context=context)
        for message_old in messages_old:
            if message_old.category_id.display_position == 'shortcut':
                TYPE.append('0')
            if message_old.category_id.display_position == 'content_left':
                TYPE.append('1')
            if message_old.category_id.display_position == 'content_right':
                TYPE.append('2')
        super(Message, self).unlink(cr, uid, ids, context=None)
        TYPE = set(TYPE)
        #refresh
        for v in TYPE:
            fresh_old = CMSFresh(v)
            fresh_old.start()
        return True

    def vote_like(self, cr, uid, user_id, message_id, context=None):
        message_vote_obj = self.pool.get('message.vote')
        message = self.read(cr, SUPERUSER_ID, int(message_id), ['vote_user_ids'], context=context)
        new_has_voted = not (user_id in message.get('vote_user_ids'))
        if new_has_voted:
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': True})
        else:
            self.write(cr, SUPERUSER_ID, [message.get('id')], {'vote_user_ids': [(3, user_id)]}, context=context)
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': True})
        return new_has_voted or False

    def vote_unlike(self, cr, uid, user_id, message_id, context=None):
        message_vote_obj = self.pool.get('message.vote')
        message = self.read(cr, SUPERUSER_ID, int(message_id), ['vote_user_ids'], context=context)
        new_has_voted = not (user_id in message.get('vote_user_ids'))
        if new_has_voted:
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': False})
        else:
            self.write(cr, SUPERUSER_ID, [message.get('id')], {'vote_user_ids': [(3, user_id)]}, context=context)
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': False})
        return new_has_voted or False
class nh_clinical_activity_access(orm.Model):
    """
    Adds an additional permission type called ``perm_responsibility``
    to an activity. This defines if a particular user group can or
    cannot perform an activity.
    """

    _name = 'nh.clinical.activity.access'
    _auto = False
    _columns = {
        'user_id':
        fields.many2one('res.users', 'User'),
        'location_ids_text':
        fields.text('Location IDS Text'),
        'parent_location_ids_text':
        fields.text('Parent Location IDS Text'),
        'location_activity_ids_text':
        fields.text('Activity IDS Text'),
        'parent_location_activity_ids_text':
        fields.text('Parent Location Activity IDS Text'),
    }

    def init(self, cr):
        cr.execute("""
            drop view if exists nh_clinical_activity_access;
            create or replace view
            nh_clinical_activity_access as(
                with
                    recursive route(level, path, parent_id, id) as (
                    select 0, id::text, parent_id, id
                    from nh_clinical_location
                    where parent_id is null
                union
                    select level + 1, path||','||location.id,
                        location.parent_id, location.id
                    from nh_clinical_location location
                    join route on location.parent_id = route.id
            ),
            location_parents as (
                select
                    id as location_id,
                    ('{'||path||'}')::int[] as ids
                from route
                order by path
            ),
            user_access as (
                select
                    u.id as user_id,
                    array_agg(access.model_id) as model_ids
                from res_users u
                inner join res_groups_users_rel gur on u.id = gur.uid
                inner join ir_model_access access
                    on access.group_id = gur.gid
                    and access.perm_responsibility = true
                group by u.id
            ),
            user_location as (
                select
                    ulr.user_id,
                    array_agg(ulr.location_id) as location_ids
                from user_location_rel ulr
                group by ulr.user_id
            ),
            user_location_parents_map as (
                select distinct
                   user_location.user_id,
                   parent_location_id
                from user_location
                inner join location_parents
                    on user_location.location_ids
                    && array[location_parents.location_id]
                inner join unnest(location_parents.ids) as parent_location_id
                    on array[parent_location_id] && location_parents.ids
            ),
            user_location_parents as (
                select
                    user_id,
                    array_agg(parent_location_id) as ids
                from user_location_parents_map
                group by user_id
            ),
            user_activity as (
                select
                    user_location.user_id,
                    array_agg(activity.id) as activity_ids
                from user_location
                inner join user_access
                    on user_location.user_id = user_access.user_id
                inner join nh_activity activity
                    on array[activity.location_id]
                    && user_location.location_ids
                inner join ir_model model on model.model = activity.data_model
                    and array[model.id] && user_access.model_ids
                group by user_location.user_id
            ),
            user_parent_location_activity as(
                select
                    user_location_parents.user_id,
                    array_agg(activity.id) as ids
                from user_location_parents
                inner join nh_activity activity
                    on array[activity.location_id] && user_location_parents.ids
                group by user_location_parents.user_id
            )
            select
                user_access.user_id as id,
                user_access.user_id,
                user_location.location_ids::text as location_ids_text,
                user_location_parents.ids::text as parent_location_ids_text,
                user_activity.activity_ids::text as location_activity_ids_text,
                user_parent_location_activity.ids::text
                    as parent_location_activity_ids_text,
                user_location.location_ids as location_ids,
                user_location_parents.ids as parent_location_ids,
                user_activity.activity_ids as location_activity_ids,
                user_parent_location_activity.ids
                    as parent_location_activity_ids
            from user_access
        inner join user_location on user_location.user_id = user_access.user_id
        inner join user_activity on user_activity.user_id = user_access.user_id
        inner join user_location_parents
            on user_location_parents.user_id = user_access.user_id
        inner join user_parent_location_activity
            on user_parent_location_activity.user_id = user_access.user_id
        ); """)
class nh_activity(orm.Model):
    """
    Extends class :class:`nh_activity<activity.nh_activity>`.
    """

    _name = 'nh.activity'
    _inherit = 'nh.activity'

    _columns = {
        'user_ids':
        fields.many2many('res.users',
                         'activity_user_rel',
                         'activity_id',
                         'user_id',
                         'Users',
                         readonly=True),
        'patient_id':
        fields.many2one('nh.clinical.patient', 'Patient', readonly=True),
        'location_id':
        fields.many2one('nh.clinical.location', 'Location', readonly=True),
        'location_name':
        fields.related('location_id',
                       'full_name',
                       type='char',
                       size=150,
                       string='Location Name'),
        'pos_id':
        fields.many2one('nh.clinical.pos', 'POS', readonly=True),
        'spell_activity_id':
        fields.many2one('nh.activity', 'Spell Activity', readonly=True),
        'cancel_reason_id':
        fields.many2one('nh.cancel.reason', 'Cancellation Reason'),
        'ward_manager_id':
        fields.many2one('res.users',
                        'Ward Manager of the ward on Complete/Cancel')
    }

    def create(self, cr, uid, vals, context=None):
        """
        Extends Odoo's `create()` method.

        Writes ``user_ids`` for responsible users of the activities`
        location.

        :param vals: values to create record
        :type vals: doct
        :returns: :class:`nh_activity<activity.nh_activity>` id
        :rtype: int
        """
        res = super(nh_activity, self).create(cr, uid, vals, context=context)
        if vals.get('location_id'):
            user_ids = self.pool['nh.activity.data'].get_activity_user_ids(
                cr, uid, res, context=context)
            if vals.get('data_model') == 'nh.clinical.spell':
                self.update_users(cr, uid, user_ids)
            else:
                self.write(cr, uid, res, {'user_ids': [[6, False, user_ids]]})
        return res

    def write(self, cr, uid, ids, values, context=None):
        """
        Extends Odoo's `write()` method.

        Also writes ``user_ids`` for responsible users of the
        activities' location. See class
        :mod:`nh_clinical_location<base.nh_clinical_location>`.

        :param ids: :class:`nh_activity<activity.nh_activity>`
            record ids
        :type ids: list
        :param vals: values to update records (may include
            ``location_id``)
        :type vals: dict
        :returns: ``True``
        :rtype: bool
        """

        if not values:
            values = {}
        res = super(nh_activity, self).write(cr,
                                             uid,
                                             ids,
                                             values,
                                             context=context)
        if 'location_id' in values:
            location_pool = self.pool['nh.clinical.location']
            location = location_pool.read(cr,
                                          uid,
                                          values['location_id'], ['user_ids'],
                                          context=context)
            if location:
                self.write(cr,
                           uid,
                           ids,
                           {'user_ids': [[6, False, location['user_ids']]]},
                           context=context)
        return res

    def cancel_open_activities(self, cr, uid, parent_id, model, context=None):
        """
        Cancels all open activities of parent activity.

        :param parent_id: id of the parent activity
        :type parent_id: int
        :param model: model (type) of activity
        :type model: str
        :returns: ``True`` if all open activities are cancelled or if
            there are no open activities. Otherwise, ``False``
        :rtype: bool
        """

        domain = [('parent_id', '=', parent_id), ('data_model', '=', model),
                  ('state', 'not in', ['completed', 'cancelled'])]
        open_activity_ids = self.search(cr, uid, domain, context=context)
        return all([
            self.cancel(cr, uid, a, context=context) for a in open_activity_ids
        ])

    def update_users(self, cr, uid, user_ids):
        """
        Updates activities with the user_ids of users responsible for
        the activities' locations.

        :param user_ids: user ids. See class
            :class:`res_users<base.res_users>`
        :type user_ids: list
        :returns: ``True``
        :rtype: bool
        """

        if not user_ids:
            return True

        where_clause = "where user_id in (%s)" % list2sqlstr(user_ids)

        sql = """
            delete from activity_user_rel {where_clause};
            insert into activity_user_rel
            select activity_id, user_id from
                (select distinct on (activity.id, ulr.user_id)
                        activity.id as activity_id,
                        ulr.user_id
                from user_location_rel ulr
                inner join res_groups_users_rel gur on ulr.user_id = gur.uid
                inner join ir_model_access access on access.group_id = gur.gid
                  and access.perm_responsibility = true
                inner join ir_model model on model.id = access.model_id
                inner join nh_activity activity
                  on model.model = activity.data_model
                  and activity.location_id = ulr.location_id
                  and activity.state not in ('completed','cancelled')
                where not exists
                  (select 1 from activity_user_rel
                    where activity_id=activity.id
                    and user_id=ulr.user_id )) pairs
            {where_clause}
        """.format(where_clause=where_clause)
        cr.execute(sql)
        self.update_spell_users(cr, uid, user_ids)

        return True

    def update_spell_users(self, cr, uid, user_ids=None):
        """
        Updates spell activities with the user_ids of users
        responsible for parent locations of spell location.

        :param user_ids: user ids. See class
            :class:`res_users<base.res_users>`
        :type user_ids: list
        :returns: ``True``
        :rtype: bool
        """

        if not user_ids:
            return True

        where_clause = "where user_id in (%s)" % list2sqlstr(user_ids)

        sql = """
            with
               recursive route(level, path, parent_id, id) as (
                       select 0, id::text, parent_id, id
                       from nh_clinical_location
                       where parent_id is null
                   union
                       select level + 1, path||','||location.id,
                        location.parent_id, location.id
                       from nh_clinical_location location
                       join route on location.parent_id = route.id
               ),
               parent_location as (
                   select
                       id as location_id,
                       ('{'||path||'}')::int[] as ids
                   from route
                   order by path
               )
           insert into activity_user_rel
           select activity_id, user_id from (
               select distinct on (activity.id, ulr.user_id)
                   activity.id as activity_id,
                   ulr.user_id
               from user_location_rel ulr
               inner join res_groups_users_rel gur on ulr.user_id = gur.uid
               inner join ir_model_access access
                on access.group_id = gur.gid
                and access.perm_responsibility = true
               inner join ir_model model
                on model.id = access.model_id
                and model.model = 'nh.clinical.spell'
               inner join parent_location
                on parent_location.ids  && array[ulr.location_id]
               inner join nh_activity activity
                on model.model = activity.data_model
                and activity.location_id = parent_location.location_id
               where not exists
                (select 1 from activity_user_rel
                where activity_id=activity.id and user_id=ulr.user_id )) pairs
           %s
        """ % where_clause

        cr.execute(sql)
        return True
    def _setup_bound_dimension(cls, dimension, columns, defaults, orm_name, name, bases, nmspc):
        """Bind a dimension to the model, creating a code for each record."""

        if dimension is True:
            dimension = {}
        elif isinstance(dimension, basestring):
            dimension = {"name": dimension}

        dimension_name = dimension.get("name", None)
        if dimension_name is None:
            dimension_name = nmspc.get("_description", False) or orm_name

        column = dimension.get("column", "analytic_id")

        ref_module = dimension.get("ref_module", "")

        ref_id = dimension.get("ref_id", None)
        if ref_id is None:
            ref_id = orm_name.replace(".", "_") + "_analytic_dimension_id"

        # To use an inherited, renamed parent field, you have to give its name.
        sync_parent = dimension.get("sync_parent", False)
        if sync_parent is True:
            sync_parent = nmspc.get("_parent_name", "parent_id")

        rel_name = dimension.get("rel_name", tuple())
        if rel_name is True:
            rel_name = u"Name"
        if isinstance(rel_name, basestring):
            rel_name = (rel_name, "name")

        rel_description = dimension.get("rel_description", tuple())
        if rel_description is True:
            rel_description = u"Description"
        if isinstance(rel_description, basestring):
            rel_description = (rel_description, "description")

        rel_active = dimension.get("rel_active", tuple())
        if rel_active is True:
            rel_active = u"Active"
        if isinstance(rel_active, basestring):
            rel_active = (rel_active, "active")

        rel_view_type = dimension.get("rel_view_type", tuple())
        if rel_view_type is True:
            rel_view_type = u"View type"
        if isinstance(rel_view_type, basestring):
            rel_view_type = (rel_view_type, "view_type")

        rel_disabled_per_company = dimension.get("rel_disabled_per_company", tuple())
        if rel_disabled_per_company is True:
            rel_disabled_per_company = u"Disabled in my company"
        if isinstance(rel_disabled_per_company, basestring):
            rel_disabled_per_company = (rel_disabled_per_company, "disabled_per_company")

        # By default, only use inherits if we can be sure there is no conflict
        # on the required fields 'name' and 'nd_id'.
        # There can still be conflicts on analytic_code's optional fields.
        use_inherits = dimension.get("use_inherits", None)
        if use_inherits is None:
            use_inherits = not (
                any(col in columns for col in ("name", "nd_id"))
                or nmspc.get("_inherits", False)
                or nmspc.get("_inherit", False)
            )

        use_code_name_methods = dimension.get("use_code_name_methods", False)

        code_ref_ids = dimension.get("code_ref_ids", False)
        if code_ref_ids is True:
            code_ref_ids = ref_id

        code_ref_module = dimension.get("code_ref_module", "")

        if use_inherits:
            inherits = nmspc.get("_inherits", {})
            inherits["analytic.code"] = column
            nmspc["_inherits"] = inherits

        # Default column for the underlying analytic code.
        if column not in columns:
            columns[column] = fields.many2one(
                "analytic.code", u"Bound Analytic Code", required=True, ondelete="restrict"
            )

        rel_cols = [
            cols
            for cols in [
                rel_name + ("name", "char", True, ""),
                rel_description + ("description", "char", False, ""),
                rel_active + ("active", "boolean", False, True),
                rel_view_type + ("view_type", "boolean", False, False),
            ]
            if len(cols) == 6
        ]

        if rel_cols:
            # NOT a method nor a class member. 'self' is the analytic_code OSV.
            def _record_from_code_id(self, cr, uid, ids, context=None):
                """Get the entries to update from the modified codes."""
                osv = self.pool.get(orm_name)
                domain = [(column, "in", ids)]
                return osv.search(cr, uid, domain, context=context)

            for string, model_col, code_col, dtype, req, default in rel_cols:
                columns[model_col] = fields.related(
                    column,
                    code_col,
                    string=string,
                    type=dtype,
                    relation="analytic.code",
                    required=req,
                    store={"analytic.code": (_record_from_code_id, [code_col], 10)},
                )
                if model_col not in defaults:
                    defaults[model_col] = default

        # In order to preserve inheritance, possible overrides, and OEMetaSL's
        # expected behavior, work on a new class that inherits the given bases,
        # then make our model class inherit from this class.
        superclass_name = "_{name}_SuperDimension".format(name=name)
        # Set _register to False in order to prevent its instantiation.
        superclass = type(superclass_name, bases, {"_register": False})

        @AddMethod(superclass)
        def __init__(self, pool, cr):
            """Load or create the analytic dimension bound to the model."""

            super(superclass, self).__init__(pool, cr)

            data_osv = self.pool["ir.model.data"]
            try:
                self._bound_dimension_id = data_osv.get_object_reference(cr, SUPERUSER_ID, ref_module, ref_id)[1]
            except ValueError:
                vals = {"name": dimension_name, "validated": True}
                self._bound_dimension_id = data_osv._update(
                    cr, SUPERUSER_ID, "analytic.dimension", ref_module, vals, xml_id=ref_id, noupdate=True
                )

        if code_ref_ids:
            prefix = config.get_misc("analytic", "code_ref_prefix", False)

            # This function is called as a method and can be overridden.
            @AddMethod(superclass)
            def _generate_code_ref_id(self, cr, uid, ids, context=None):
                data_osv = self.pool["ir.model.data"]
                records = self.browse(cr, uid, ids, context=None)
                if not isinstance(records, list):
                    records = [records]

                for record in records:
                    code = record[column]
                    code_ref_id_builder = [prefix] if prefix else []
                    if "company_id" in record and record.company_id:
                        code_ref_id_builder.append(record.company_id.code)
                    code_ref_id_builder.append("ANC")
                    code_ref_id_builder.append(code_ref_ids)
                    code_ref_id_builder.append(code.name)

                    vals = {
                        "name": "_".join(code_ref_id_builder),
                        "module": code_ref_module,
                        "model": "analytic.code",
                        "res_id": code.id,
                    }
                    data_osv.create(cr, uid, vals, context=context)

        @AddMethod(superclass)
        def create(self, cr, uid, vals, context=None):
            """Create the analytic code."""

            code_vals = {}

            if sync_parent:
                cp = self._get_code_parent(cr, uid, vals, context=context)
                if cp is not None:
                    code_vals["code_parent_id"] = cp

            # Direct changes to the 'bound analytic code' field are ignored
            # unless the 'force_code_id' context key is passed as True.
            force_code_id = vals.pop(column, False)

            if context and context.get("force_code_id", False) == True:
                self._force_code(cr, uid, force_code_id, code_vals, context)
                vals[column] = force_code_id

            else:
                if use_inherits:
                    code_vals.update(vals)
                else:
                    code_vals["name"] = vals.get("name")

                # OpenERP bug: related fields do not work properly on creation.
                for rel in rel_cols:
                    model_col, code_col = rel[1:3]
                    if model_col in vals:
                        code_vals[code_col] = vals[model_col]
                    elif model_col in self._defaults:
                        code_vals[code_col] = self._defaults[model_col]

                # We have to create the code separately, even with inherits.
                code_osv = self.pool["analytic.code"]
                code_vals["nd_id"] = self._bound_dimension_id
                code_id = code_osv.create(cr, uid, code_vals, context=context)
                vals[column] = code_id

            res = super(superclass, self).create(cr, uid, vals, context=context)

            if code_ref_ids:
                self._generate_code_ref_id(cr, uid, res, context=context)

            return res

        @AddMethod(superclass)
        def write(self, cr, uid, ids, vals, context=None):
            """Update the analytic code's name if it is not inherited,
            and its parent code if parent-child relations are synchronized.
            """

            code_vals = {}
            new = False

            if not isinstance(ids, (list, tuple)):
                ids = [ids]

            if sync_parent:
                cp = self._get_code_parent(cr, uid, vals, context=context)
                if cp is not None:
                    code_vals["code_parent_id"] = cp

            # Direct changes to the 'bound analytic code' field are ignored
            # unless the 'force_code_id' context key is passed as True.
            force_code_id = vals.pop(column, False)

            if context and context.get("force_code_id", False) == True:
                self._force_code(cr, uid, force_code_id, code_vals, context)
                vals[column] = force_code_id

            elif use_inherits:
                vals.update(code_vals)

            else:
                name_col = rel_name[1] if rel_name else "name"
                if name_col in vals:
                    code_vals["name"] = vals[name_col]
                records = self.browse(cr, uid, ids, context=context)
                code_ids = [getattr(rec, column).id for rec in records]

                # If updating a single record with no code, create it.
                code_osv = self.pool["analytic.code"]
                if code_ids == [False]:
                    new = ids[0]
                    code_vals["nd_id"] = self._bound_dimension_id
                    if "name" not in code_vals:
                        code_vals["name"] = self.read(cr, uid, new, [name_col], context=context)[name_col]
                    vals[column] = code_osv.create(cr, uid, code_vals, context=context)
                elif code_vals:
                    code_osv.write(cr, uid, code_ids, code_vals, context=context)

            res = super(superclass, self).write(cr, uid, ids, vals, context=context)

            if code_ref_ids and new is not False:
                self._generate_code_ref_id(cr, uid, new, context=context)

            return res

        @AddMethod(superclass)
        def _force_code(self, cr, uid, force_code_id, code_vals, context=None):

            code_osv = self.pool["analytic.code"]

            if not force_code_id:
                raise ValueError(
                    "An analytic code ID MUST be specified if the " "force_code_id key is enabled in the context"
                )
            force_code_dim = code_osv.read(cr, uid, force_code_id, ["nd_id"], context=context)["nd_id"][0]
            if force_code_dim != self._bound_dimension_id:
                raise ValueError(
                    "If specified, codes must belong to the bound " "analytic dimension {}".format(dimension_name)
                )
            if code_vals:
                code_osv.write(cr, uid, force_code_id, code_vals, context=context)

        if sync_parent:
            # This function is called as a method and can be overridden.
            @AddMethod(superclass)
            def _get_code_parent(self, cr, uid, vals, context=None):
                """If parent_id is in the submitted values, return the analytic
                code of this parent, to be used as the child's code's parent.
                """
                parent_id = vals.get(sync_parent, None)
                if parent_id is not None:
                    if parent_id:
                        res = self.read(cr, uid, parent_id, [column], context=context)[column]
                        return res[0] if res else False
                    else:
                        return False
                return None

        if use_code_name_methods:

            @AddMethod(superclass)
            def name_get(self, cr, uid, ids, context=None):
                """Return the analytic code's name."""

                code_osv = self.pool.get("analytic.code")
                code_reads = self.read(cr, uid, ids, [column], context=context)
                c2m = {  # Code IDs to model IDs
                    code_read[column][0]: code_read["id"] for code_read in code_reads if code_read[column] is not False
                }
                names = code_osv.name_get(cr, uid, c2m.keys(), context=context)
                return [(c2m[cid], name) for cid, name in names if cid in c2m]

            @AddMethod(superclass)
            def name_search(self, cr, uid, name, args=None, operator="ilike", context=None, limit=100):
                """Return the records whose analytic code matches the name."""

                code_osv = self.pool.get("analytic.code")
                args.append(("nd_id", "=", self._bound_dimension_id))
                names = code_osv.name_search(cr, uid, name, args, operator, context, limit)
                if not names:
                    return []
                dom = [(column, "in", zip(*names)[0])]
                ids = self.search(cr, uid, dom, context=context)
                code_reads = self.read(cr, uid, ids, [column], context=context)
                c2m = {  # Code IDs to model IDs
                    code_read[column][0]: code_read["id"] for code_read in code_reads if code_read[column] is not False
                }
                return [(c2m[cid], cname) for cid, cname in names if cid in c2m]

        return (superclass,)
Example #16
0
class procurement_order(osv.osv):
    _inherit = "procurement.order"
    _columns = {
        'location_id':
        fields.many2one(
            'stock.location', 'Procurement Location'
        ),  # not required because task may create procurements that aren't linked to a location with sale_service
        'partner_dest_id':
        fields.many2one(
            'res.partner',
            'Customer Address',
            help=
            "In case of dropshipping, we need to know the destination address more precisely"
        ),
        'move_ids':
        fields.one2many('stock.move',
                        'procurement_id',
                        'Moves',
                        help="Moves created by the procurement"),
        'move_dest_id':
        fields.many2one('stock.move',
                        'Destination Move',
                        help="Move which caused (created) the procurement"),
        'route_ids':
        fields.many2many(
            'stock.location.route',
            'stock_location_route_procurement',
            'procurement_id',
            'route_id',
            'Preferred Routes',
            help=
            "Preferred route to be followed by the procurement order. Usually copied from the generating document (SO) but could be set up manually."
        ),
        'warehouse_id':
        fields.many2one('stock.warehouse',
                        'Warehouse',
                        help="Warehouse to consider for the route selection"),
        'orderpoint_id':
        fields.many2one('stock.warehouse.orderpoint', 'Minimum Stock Rule'),
    }

    def propagate_cancel(self, cr, uid, procurement, context=None):
        if procurement.rule_id.action == 'move' and procurement.move_ids:
            self.pool.get('stock.move').action_cancel(
                cr, uid, [m.id for m in procurement.move_ids], context=context)

    def cancel(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        to_cancel_ids = self.get_cancel_ids(cr, uid, ids, context=context)
        ctx = context.copy()
        #set the context for the propagation of the procurement cancelation
        ctx['cancel_procurement'] = True
        for procurement in self.browse(cr, uid, to_cancel_ids, context=ctx):
            self.propagate_cancel(cr, uid, procurement, context=ctx)
        return super(procurement_order, self).cancel(cr,
                                                     uid,
                                                     to_cancel_ids,
                                                     context=ctx)

    def _find_parent_locations(self, cr, uid, procurement, context=None):
        location = procurement.location_id
        res = [location.id]
        while location.location_id:
            location = location.location_id
            res.append(location.id)
        return res

    def change_warehouse_id(self, cr, uid, ids, warehouse_id, context=None):
        if warehouse_id:
            warehouse = self.pool.get('stock.warehouse').browse(
                cr, uid, warehouse_id, context=context)
            return {'value': {'location_id': warehouse.lot_stock_id.id}}
        return {}

    def _search_suitable_rule(self,
                              cr,
                              uid,
                              procurement,
                              domain,
                              context=None):
        '''we try to first find a rule among the ones defined on the procurement order group and if none is found, we try on the routes defined for the product, and finally we fallback on the default behavior'''
        pull_obj = self.pool.get('procurement.rule')
        warehouse_route_ids = []
        if procurement.warehouse_id:
            domain += [
                '|', ('warehouse_id', '=', procurement.warehouse_id.id),
                ('warehouse_id', '=', False)
            ]
            warehouse_route_ids = [
                x.id for x in procurement.warehouse_id.route_ids
            ]
        product_route_ids = [
            x.id for x in procurement.product_id.route_ids +
            procurement.product_id.categ_id.total_route_ids
        ]
        procurement_route_ids = [x.id for x in procurement.route_ids]
        res = pull_obj.search(cr,
                              uid,
                              domain +
                              [('route_id', 'in', procurement_route_ids)],
                              order='route_sequence, sequence',
                              context=context)
        if not res:
            res = pull_obj.search(cr,
                                  uid,
                                  domain +
                                  [('route_id', 'in', product_route_ids)],
                                  order='route_sequence, sequence',
                                  context=context)
            if not res:
                res = warehouse_route_ids and pull_obj.search(
                    cr,
                    uid,
                    domain + [('route_id', 'in', warehouse_route_ids)],
                    order='route_sequence, sequence',
                    context=context) or []
                if not res:
                    res = pull_obj.search(cr,
                                          uid,
                                          domain + [('route_id', '=', False)],
                                          order='sequence',
                                          context=context)
        return res

    def _find_suitable_rule(self, cr, uid, procurement, context=None):
        rule_id = super(procurement_order,
                        self)._find_suitable_rule(cr,
                                                  uid,
                                                  procurement,
                                                  context=context)
        if not rule_id:
            #a rule defined on 'Stock' is suitable for a procurement in 'Stock\Bin A'
            all_parent_location_ids = self._find_parent_locations(
                cr, uid, procurement, context=context)
            rule_id = self._search_suitable_rule(
                cr,
                uid,
                procurement, [('location_id', 'in', all_parent_location_ids)],
                context=context)
            rule_id = rule_id and rule_id[0] or False
        return rule_id

    def _run_move_create(self, cr, uid, procurement, context=None):
        ''' Returns a dictionary of values that will be used to create a stock move from a procurement.
        This function assumes that the given procurement has a rule (action == 'move') set on it.

        :param procurement: browse record
        :rtype: dictionary
        '''
        newdate = (
            datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') -
            relativedelta(days=procurement.rule_id.delay or 0)
        ).strftime('%Y-%m-%d %H:%M:%S')
        group_id = False
        if procurement.rule_id.group_propagation_option == 'propagate':
            group_id = procurement.group_id and procurement.group_id.id or False
        elif procurement.rule_id.group_propagation_option == 'fixed':
            group_id = procurement.rule_id.group_id and procurement.rule_id.group_id.id or False
        #it is possible that we've already got some move done, so check for the done qty and create
        #a new move with the correct qty
        already_done_qty = 0
        already_done_qty_uos = 0
        for move in procurement.move_ids:
            already_done_qty += move.product_uom_qty if move.state == 'done' else 0
            already_done_qty_uos += move.product_uos_qty if move.state == 'done' else 0
        qty_left = max(procurement.product_qty - already_done_qty, 0)
        qty_uos_left = max(procurement.product_uos_qty - already_done_qty_uos,
                           0)
        vals = {
            'name':
            procurement.name,
            'company_id':
            procurement.rule_id.company_id.id
            or procurement.rule_id.location_src_id.company_id.id
            or procurement.rule_id.location_id.company_id.id
            or procurement.company_id.id,
            'product_id':
            procurement.product_id.id,
            'product_uom':
            procurement.product_uom.id,
            'product_uom_qty':
            qty_left,
            'product_uos_qty': (procurement.product_uos and qty_uos_left)
            or qty_left,
            'product_uos':
            (procurement.product_uos and procurement.product_uos.id)
            or procurement.product_uom.id,
            'partner_id':
            procurement.rule_id.partner_address_id.id
            or (procurement.group_id and procurement.group_id.partner_id.id)
            or False,
            'location_id':
            procurement.rule_id.location_src_id.id,
            'location_dest_id':
            procurement.location_id.id,
            'move_dest_id':
            procurement.move_dest_id and procurement.move_dest_id.id or False,
            'procurement_id':
            procurement.id,
            'rule_id':
            procurement.rule_id.id,
            'procure_method':
            procurement.rule_id.procure_method,
            'origin':
            procurement.origin,
            'picking_type_id':
            procurement.rule_id.picking_type_id.id,
            'group_id':
            group_id,
            'route_ids': [(4, x.id) for x in procurement.route_ids],
            'warehouse_id':
            procurement.rule_id.propagate_warehouse_id.id
            or procurement.rule_id.warehouse_id.id,
            'date':
            newdate,
            'date_expected':
            newdate,
            'propagate':
            procurement.rule_id.propagate,
            'priority':
            procurement.priority,
        }
        return vals

    def _run(self, cr, uid, procurement, context=None):
        if procurement.rule_id and procurement.rule_id.action == 'move':
            if not procurement.rule_id.location_src_id:
                self.message_post(cr,
                                  uid, [procurement.id],
                                  body=_('No source location defined!'),
                                  context=context)
                return False
            move_obj = self.pool.get('stock.move')
            move_dict = self._run_move_create(cr,
                                              uid,
                                              procurement,
                                              context=context)
            #create the move as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example)
            move_obj.create(cr, SUPERUSER_ID, move_dict, context=context)
            return True
        return super(procurement_order, self)._run(cr,
                                                   uid,
                                                   procurement,
                                                   context=context)

    def run(self, cr, uid, ids, autocommit=False, context=None):
        new_ids = [
            x.id for x in self.browse(cr, uid, ids, context=context)
            if x.state not in ('running', 'done', 'cancel')
        ]
        res = super(procurement_order, self).run(cr,
                                                 uid,
                                                 new_ids,
                                                 autocommit=autocommit,
                                                 context=context)

        #after all the procurements are run, check if some created a draft stock move that needs to be confirmed
        #(we do that in batch because it fasts the picking assignation and the picking state computation)
        move_to_confirm_ids = []
        for procurement in self.browse(cr, uid, new_ids, context=context):
            if procurement.state == "running" and procurement.rule_id and procurement.rule_id.action == "move":
                move_to_confirm_ids += [
                    m.id for m in procurement.move_ids if m.state == 'draft'
                ]
        if move_to_confirm_ids:
            self.pool.get('stock.move').action_confirm(cr,
                                                       uid,
                                                       move_to_confirm_ids,
                                                       context=context)
        return res

    def _check(self, cr, uid, procurement, context=None):
        ''' Implement the procurement checking for rules of type 'move'. The procurement will be satisfied only if all related
            moves are done/cancel and if the requested quantity is moved.
        '''
        if procurement.rule_id and procurement.rule_id.action == 'move':
            uom_obj = self.pool.get('product.uom')
            # In case Phantom BoM splits only into procurements
            if not procurement.move_ids:
                return True
            cancel_test_list = [
                x.state == 'cancel' for x in procurement.move_ids
            ]
            done_cancel_test_list = [
                x.state in ('done', 'cancel') for x in procurement.move_ids
            ]
            at_least_one_cancel = any(cancel_test_list)
            all_done_or_cancel = all(done_cancel_test_list)
            all_cancel = all(cancel_test_list)
            if not all_done_or_cancel:
                return False
            elif all_done_or_cancel and not all_cancel:
                return True
            elif all_cancel:
                self.message_post(
                    cr,
                    uid, [procurement.id],
                    body=
                    _('All stock moves have been cancelled for this procurement.'
                      ),
                    context=context)
            self.write(cr,
                       uid, [procurement.id], {'state': 'cancel'},
                       context=context)
            return False

        return super(procurement_order, self)._check(cr, uid, procurement,
                                                     context)

    def do_view_pickings(self, cr, uid, ids, context=None):
        '''
        This function returns an action that display the pickings of the procurements belonging
        to the same procurement group of given ids.
        '''
        mod_obj = self.pool.get('ir.model.data')
        act_obj = self.pool.get('ir.actions.act_window')
        result = mod_obj.get_object_reference(cr, uid, 'stock',
                                              'do_view_pickings')
        id = result and result[1] or False
        result = act_obj.read(cr, uid, [id], context=context)[0]
        group_ids = set([
            proc.group_id.id
            for proc in self.browse(cr, uid, ids, context=context)
            if proc.group_id
        ])
        result['domain'] = "[('group_id','in',[" + ','.join(
            map(str, list(group_ids))) + "])]"
        return result

    def run_scheduler(self,
                      cr,
                      uid,
                      use_new_cursor=False,
                      company_id=False,
                      context=None):
        '''
        Call the scheduler in order to check the running procurements (super method), to check the minimum stock rules
        and the availability of moves. This function is intended to be run for all the companies at the same time, so
        we run functions as SUPERUSER to avoid intercompanies and access rights issues.

        @param self: The object pointer
        @param cr: The current row, from the database cursor,
        @param uid: The current user ID for security checks
        @param ids: List of selected IDs
        @param use_new_cursor: if set, use a dedicated cursor and auto-commit after processing each procurement.
            This is appropriate for batch jobs only.
        @param context: A standard dictionary for contextual values
        @return:  Dictionary of values
        '''
        super(procurement_order,
              self).run_scheduler(cr,
                                  uid,
                                  use_new_cursor=use_new_cursor,
                                  company_id=company_id,
                                  context=context)
        if context is None:
            context = {}
        try:
            if use_new_cursor:
                cr = openerp.registry(cr.dbname).cursor()

            move_obj = self.pool.get('stock.move')

            #Minimum stock rules
            self._procure_orderpoint_confirm(cr,
                                             SUPERUSER_ID,
                                             use_new_cursor=use_new_cursor,
                                             company_id=company_id,
                                             context=context)

            #Search all confirmed stock_moves and try to assign them
            confirmed_ids = move_obj.search(
                cr,
                uid, [('state', '=', 'confirmed')],
                limit=None,
                order='priority desc, date_expected asc',
                context=context)
            for x in xrange(0, len(confirmed_ids), 100):
                move_obj.action_assign(cr,
                                       uid,
                                       confirmed_ids[x:x + 100],
                                       context=context)
                if use_new_cursor:
                    cr.commit()

            if use_new_cursor:
                cr.commit()
        finally:
            if use_new_cursor:
                try:
                    cr.close()
                except Exception:
                    pass
        return {}

    def _get_orderpoint_date_planned(self,
                                     cr,
                                     uid,
                                     orderpoint,
                                     start_date,
                                     context=None):
        date_planned = start_date + relativedelta(
            days=orderpoint.product_id.seller_delay or 0.0)
        return date_planned.strftime(DEFAULT_SERVER_DATE_FORMAT)

    def _prepare_orderpoint_procurement(self,
                                        cr,
                                        uid,
                                        orderpoint,
                                        product_qty,
                                        context=None):
        return {
            'name':
            orderpoint.name,
            'date_planned':
            self._get_orderpoint_date_planned(cr,
                                              uid,
                                              orderpoint,
                                              datetime.today(),
                                              context=context),
            'product_id':
            orderpoint.product_id.id,
            'product_qty':
            product_qty,
            'company_id':
            orderpoint.company_id.id,
            'product_uom':
            orderpoint.product_uom.id,
            'location_id':
            orderpoint.location_id.id,
            'origin':
            orderpoint.name,
            'warehouse_id':
            orderpoint.warehouse_id.id,
            'orderpoint_id':
            orderpoint.id,
            'group_id':
            orderpoint.group_id.id,
        }

    def _product_virtual_get(self, cr, uid, order_point):
        product_obj = self.pool.get('product.product')
        return product_obj._product_available(
            cr,
            uid, [order_point.product_id.id],
            context={'location': order_point.location_id.id
                     })[order_point.product_id.id]['virtual_available']

    def _procure_orderpoint_confirm(self,
                                    cr,
                                    uid,
                                    use_new_cursor=False,
                                    company_id=False,
                                    context=None):
        '''
        Create procurement based on Orderpoint

        :param bool use_new_cursor: if set, use dedicated cursors and auto-commit after processing
            100 orderpoints.
            This is appropriate for batch jobs only.
        '''
        if context is None:
            context = {}
        orderpoint_obj = self.pool.get('stock.warehouse.orderpoint')

        procurement_obj = self.pool.get('procurement.order')
        dom = company_id and [('company_id', '=', company_id)] or []
        orderpoint_ids = orderpoint_obj.search(cr, uid, dom, context=context)
        prev_ids = []
        while orderpoint_ids:
            ids = orderpoint_ids[:100]
            del orderpoint_ids[:100]
            if use_new_cursor:
                cr = openerp.registry(cr.dbname).cursor()
            for op in orderpoint_obj.browse(cr, uid, ids, context=context):
                try:
                    prods = self._product_virtual_get(cr, uid, op)
                    if prods is None:
                        continue
                    if float_compare(
                            prods,
                            op.product_min_qty,
                            precision_rounding=op.product_uom.rounding) < 0:
                        qty = max(op.product_min_qty,
                                  op.product_max_qty) - prods
                        reste = op.qty_multiple > 0 and qty % op.qty_multiple or 0.0
                        if float_compare(reste,
                                         0.0,
                                         precision_rounding=op.product_uom.
                                         rounding) > 0:
                            qty += op.qty_multiple - reste

                        if float_compare(qty,
                                         0.0,
                                         precision_rounding=op.product_uom.
                                         rounding) <= 0:
                            continue

                        qty -= orderpoint_obj.subtract_procurements(
                            cr, uid, op, context=context)

                        qty_rounded = float_round(
                            qty, precision_rounding=op.product_uom.rounding)
                        if qty_rounded > 0:
                            proc_id = procurement_obj.create(
                                cr,
                                uid,
                                self._prepare_orderpoint_procurement(
                                    cr, uid, op, qty_rounded, context=context),
                                context=context)
                            self.check(cr, uid, [proc_id], context=context)
                            self.run(cr, uid, [proc_id], context=context)
                    if use_new_cursor:
                        cr.commit()
                except OperationalError:
                    if use_new_cursor:
                        orderpoint_ids.append(op.id)
                        cr.rollback()
                        continue
                    else:
                        raise
            if use_new_cursor:
                cr.commit()
                cr.close()
            if prev_ids == ids:
                break
            else:
                prev_ids = ids

        return {}
Example #17
0
    def _method_get(self, cr, uid, context=None):
        res = super(sale_order, self)._method_get(cr, uid, context=context)
        res.append(('ups.account', 'UPS'))
        return res
    
    _columns = {
        'payment_method':fields.selection([
            ('cc_pre_auth', 'Credit Card – PreAuthorized'),
            ('invoice', 'Invoice'),
            ('cod', 'COD'),
            ('p_i_a', 'Pay In Advance'),
            ('pay_pal', 'Paypal'),
            ('no_charge', 'No Charge')], 'Payment Method'),
        'ship_company_code': fields.selection(_get_company_code, 'Logistic Company', method=True, size=64),
<<<<<<< HEAD
        'ups_shipper_id': fields.many2one('ups.account.shipping', 'Shipping Account'),
=======
        'ups_shipper_id': fields.many2one('ups.account.shipping', 'Shipper'),
>>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d
        'ups_service_id': fields.many2one('ups.shipping.service.type', 'Service Type'),
        'ups_pickup_type': fields.selection([
            ('01', 'Daily Pickup'),
            ('03', 'Customer Counter'),
            ('06', 'One Time Pickup'),
            ('07', 'On Call Air'),
            ('11', 'Suggested Retail Rates'),
            ('19', 'Letter Center'),
            ('20', 'Air Service Center'),
            ], 'Pickup Type'),
        'ups_packaging_type': fields.many2one('shipping.package.type', 'Packaging Type'),
        'shipping_rates': fields.one2many('shipping.rates.sales', 'sales_id', 'Rate Quotes'),
Example #18
0
class procurement_group(osv.osv):
    _inherit = 'procurement.group'
    _columns = {'partner_id': fields.many2one('res.partner', 'Partner')}
Example #19
0
  - The 'Invoice From The Picking' choice is used to create an invoice during the picking process."""),
        'state': fields.selection([
            ('draft', 'Draft Quotation'),
            ('sent', 'Quotation Sent'),
            ('cancel', 'Cancelled'),
            ('waiting_date', 'Waiting Schedule'),
            ('progress', 'Sales Order'),
            ('cc_auth', 'Draft Authorized'),
            ('manual', 'Sale to Invoice'),
            ('invoice_except', 'Invoice Exception'),
            ('shipping_except', 'Shipping Exception'),
            ('done', 'Done')
            ], 'Status', readonly=True, track_visibility='onchange',
            help="Gives the status of the quotation or sales order. \nThe exception status is automatically set when a cancel operation occurs in the processing of a document linked to the sales order. \nThe 'Waiting Schedule' status is set when the invoice is confirmed but waiting for the scheduler to run on the order date.", select=True),
        'cc_pre_auth':fields.boolean('Creditcard Pre-authorised'),
        'rel_account_voucher_id':fields.many2one('account.voucher', 'Related Payment'),
        'invoiced': fields.function(_invoiced, method=True, string='Paid',
        type='boolean', help="It indicates that an invoice has been paid.",
        store={
             'account.invoice'  : (_get_invoice, ['state'], 20),
             'sale.order'       : (lambda self, cr, uid, ids, c={}: ids, ['state'], 20),
             'account.voucher'  : (_get_voucher, ['state'], 20),
         }),
        'cc_ship_refund' : fields.boolean('Ship Refunded', readonly=True),
    }

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None:
            default = {}
        if context is None:
            context = {}
Example #20
0
class procurement_rule(osv.osv):
    _inherit = 'procurement.rule'

    def _get_action(self, cr, uid, context=None):
        result = super(procurement_rule, self)._get_action(cr,
                                                           uid,
                                                           context=context)
        return result + [('move', _('Move From Another Location'))]

    def _get_rules(self, cr, uid, ids, context=None):
        res = []
        for route in self.browse(cr, uid, ids):
            res += [x.id for x in route.pull_ids]
        return res

    _columns = {
        'location_id':
        fields.many2one('stock.location', 'Procurement Location'),
        'location_src_id':
        fields.many2one('stock.location',
                        'Source Location',
                        help="Source location is action=move"),
        'route_id':
        fields.many2one('stock.location.route',
                        'Route',
                        help="If route_id is False, the rule is global"),
        'procure_method':
        fields.selection(
            [('make_to_stock', 'Take From Stock'),
             ('make_to_order', 'Create Procurement')],
            'Move Supply Method',
            required=True,
            help=
            """Determines the procurement method of the stock move that will be generated: whether it will need to 'take from the available stock' in its source location or needs to ignore its stock and create a procurement over there."""
        ),
        'route_sequence':
        fields.related('route_id',
                       'sequence',
                       string='Route Sequence',
                       store={
                           'stock.location.route':
                           (_get_rules, ['sequence'], 10),
                           'procurement.rule':
                           (lambda self, cr, uid, ids, c={}: ids, ['route_id'],
                            10),
                       }),
        'picking_type_id':
        fields.many2one(
            'stock.picking.type',
            'Picking Type',
            help=
            "Picking Type determines the way the picking should be shown in the view, reports, ..."
        ),
        'delay':
        fields.integer('Number of Days'),
        'partner_address_id':
        fields.many2one('res.partner', 'Partner Address'),
        'propagate':
        fields.boolean(
            'Propagate cancel and split',
            help=
            'If checked, when the previous move of the move (which was generated by a next procurement) is cancelled or split, the move generated by this move will too'
        ),
        'warehouse_id':
        fields.many2one('stock.warehouse',
                        'Served Warehouse',
                        help='The warehouse this rule is for'),
        'propagate_warehouse_id':
        fields.many2one(
            'stock.warehouse',
            'Warehouse to Propagate',
            help=
            "The warehouse to propagate on the created move/procurement, which can be different of the warehouse this rule is for (e.g for resupplying rules from another warehouse)"
        ),
    }

    _defaults = {
        'procure_method': 'make_to_stock',
        'propagate': True,
        'delay': 0,
    }
Example #21
0
#(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 <http://www.gnu.org/licenses/>.        #
###############################################################################

from openerp.osv import orm, fields

FISCAL_POSITION_COLUMNS = {
    'name': fields.char('Fiscal Position', size=128, required=True),
    'fiscal_category_id': fields.many2one(
        'l10n_br_account.fiscal.category', 'Categoria Fiscal'),
    'fiscal_category_fiscal_type': fields.related(
        'fiscal_category_id', 'fiscal_type', type='char', readonly=True,
        relation='l10n_br_account.fiscal.category', store=True,
        string='Fiscal Type'),
    'type': fields.selection([('input', 'Entrada'), ('output', 'Saida')],
                             'Tipo'),
    'type_tax_use': fields.selection(
        [('sale', 'Sale'), ('purchase', 'Purchase'), ('all', 'All')],
        'Tax Application'),
    'inv_copy_note': fields.boolean(u'Copiar Observação na Nota Fiscal'),
    'asset_operation': fields.boolean(u'Operação de Aquisição de Ativo',
        help=u"""Caso seja marcada essa opção, será incluido o IPI na base de
            calculo do ICMS."""),
    'state': fields.selection([('draft', u'Rascunho'),
            ('review', u'Revisão'), ('approved', u'Aprovada'),
class hr_payroll_ma_bulletin_auto(osv.osv):

    _name = "hr.payroll_ma.bulletin_auto"
    _inherit = "hr.payroll_ma.bulletin"

    def get_normal_hours(self, cr, uid, ids, context=None):

        total_work = self.pool.get('hr.total.work')
        nh_ids = total_work.search(cr,
                                   uid,
                                   [('employee_name', '=', self.employee_id),
                                    ('period_id', '=', self.period_id)],
                                   context=context)
        nh = total_work.browse(cr, uid, nh_ids, context).normal_working_hours
        return nh

    def get_hs_hours(self, cr, uid, ids, context=None):

        total_work = self.pool.get('hr.total.work')
        hs_ids = total_work.search(cr,
                                   uid,
                                   [('employee_name', '=', self.employee_id),
                                    ('period_id', '=', self.period_id)],
                                   context=context)
        hs = total_work.browse(cr, uid, hs_ids, context).hs_working_hours
        return hs

    def get_working_days(self, cr, uid, ids, context=None):

        total_work = self.pool.get('hr.total.work')
        hs_ids = total_work.search(cr,
                                   uid,
                                   [('employee_name', '=', self.employee_id),
                                    ('period_id', '=', self.period_id)],
                                   context=context)
        hs = total_work.browse(cr, uid, hs_ids, context).working_days
        return hs

    _columns = {
        'employee_id':
        fields.many2one('hr.employee',
                        'Employe',
                        change_default=True,
                        readonly=False,
                        required=True,
                        select=1),

        #'normal_hours' : fields.function(get_normal_hours,type="float"),
        #'hs_hours' : fields.function(get_hs_hours,type="float"),
        #'working_days' : fields.function(get_working_days,type="float"),
        #'normal_hours' : fields.float('heures normales',readonly=True),
        'hs_hours':
        fields.float('heures supplémentaires', readonly=True),
        #'working_days' : fields.float('jours travaillés',readonly=True),
    }

    _defaults = {
        #'normal_hours': '160',
        'hs_hours': '18',
        'working_days': '20',
    }
Example #23
0
#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 <http://www.gnu.org/licenses/>.        #
###############################################################################

from openerp.osv import orm, fields

FISCAL_POSITION_COLUMNS = {
    'cfop_id': fields.many2one('l10n_br_account_product.cfop', 'CFOP'),
}


class AccountFiscalPositionTemplate(orm.Model):
    _inherit = 'account.fiscal.position.template'
    _columns = FISCAL_POSITION_COLUMNS


class AccountFiscalPosition(orm.Model):
    _inherit = 'account.fiscal.position'
    _columns = FISCAL_POSITION_COLUMNS

    #TODO - Refatorar para trocar os impostos
    def map_tax_code(self, cr, uid, product_id, fiscal_position,
                     company_id=False, tax_ids=False, context=None):
Example #24
0
class stock_warehouse(osv.osv):
    _inherit = "stock.warehouse"
    _columns = {
        'delivery_source_loc_id': fields.many2one('stock.location', 'Location Delivery Source (optional)', required=False, domain=[('usage','=','internal')],
                                                  help="If specified, Delivery Order created from Sales Order will use this as source location"),
    }
Example #25
0
models = [
    ('boolean', fields.boolean()),
    ('integer', fields.integer()),
    ('float', fields.float()),
    ('decimal', fields.float(digits=(16, 3))),
    ('string.bounded', fields.char('unknown', size=16)),
    ('string.required', fields.char('unknown', size=None, required=True)),
    ('string', fields.char('unknown', size=None)),
    ('date', fields.date()),
    ('datetime', fields.datetime()),
    ('text', fields.text()),
    ('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux"), (4, '')])),
    # here use size=-1 to store the values as integers instead of strings
    ('selection.function', fields.selection(selection_fn, size=-1)),
    # just relate to an integer
    ('many2one', fields.many2one('export.integer')),
    ('one2many', fields.one2many('export.one2many.child', 'parent_id')),
    ('many2many', fields.many2many('export.many2many.other')),
    ('function', fields.function(function_fn, fnct_inv=function_fn_write, type="integer")),
    # related: specialization of fields.function, should work the same way
    # TODO: reference
]

for name, field in models:
    class NewModel(orm.Model):
        _name = 'export.%s' % name
        _columns = {
            'const': fields.integer(),
            'value': field,
        }
        _defaults = {
class stock_partial_picking_line(orm.TransientModel):
    _inherit = "stock.partial.picking.line"

    def _get_color_line(self, cr, uid, picking_line, product_ids=[], context=None):
        if picking_line.product_id.id in product_ids:
            color = 'blue'
        elif picking_line.tracking:
            color = 'red'
        elif picking_line.line_check or context.get('line_check', False):
            color = 'grey'
        else:
            color = 'black'
        return color

    def action_check(self, cr, uid, move_ids, context):
        line = self.pool['stock.partial.picking.line'].browse(cr, uid, move_ids, context)[0]
        color = self._get_color_line(cr, uid, line, [], context)
        line_vals = {
            'line_check': not line.line_check,
            'row_color': color
        }
        line.write(line_vals)
        return True

    def action_add(self, cr, uid, move_ids, context):
        line = self.pool['stock.partial.picking.line'].browse(cr, uid, move_ids, context)[0]
        dest_qty = line.quantity + 1
        if line.move_id.product_qty >= dest_qty:
            line.write({'quantity': dest_qty})
        return True

    def action_remove(self, cr, uid, move_ids, context):
        line = self.pool['stock.partial.picking.line'].browse(cr, uid, move_ids, context)[0]
        if line.quantity >= 1.0:
            line.write({'quantity': line.quantity - 1})
        return True
        
    def _get_prodlot_code(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        for move in self.browse(cr, uid, ids):
            res[move.id] = move.prodlot_id and move.prodlot_id.name or False
        return res

    def _set_prodlot_code(self, cr, uid, ids, field_name, value, arg, context=None):
        if not value:
            return False
        
        if isinstance(ids, (int, long)):
            ids = [ids]
        
        if not hasattr(self, 'serials'):
            self.serial = {ids[0]: value}
        else:
            if not ids[0] in self.serial and value in self.serial.values():
                raise orm.except_orm(_('Warning'), (_('Serial number {number} is written more than once').format(number=value)))
            else:
                self.serials.append(value)
        
        lot_obj = self.pool['stock.production.lot']
        
        for move in self.browse(cr, uid, ids, context=context):
            product_id = move.product_id.id
            value = value.upper()
            existing_prodlot_ids = lot_obj.search(cr, uid, [('name', '=', value), ('product_id', '=', product_id)])
            if existing_prodlot_ids and not existing_prodlot_ids[0] == move.prodlot_id.id:
                raise orm.except_orm(_('Warning'), (_('Serial number "{number}" is already exists').format(number=value)))
            elif not existing_prodlot_ids:
                prodlot_id = self.pool['stock.production.lot'].create(cr, uid, {
                    'name': value,
                    'product_id': product_id,
                })
                
                move.write({'prodlot_id': int(prodlot_id)})

        return True

    def get_color(self, cr, uid, ids, field_name, arg, context):
        res = {}
        for line in self.browse(cr, uid, ids, context):
            res[line.id] = 'black'
            if line.tracking:
                res[line.id] = 'red'
        return res

    def _product_code(self, cr, uid, ids, name, arg, context=None):
        res = {}
        if context is None:
            context = {}
        product_obj = self.pool['product.product']

        for line in self.browse(cr, uid, ids, context=context):
            partner_id = line.move_id.partner_id and line.move_id.partner_id.id or None
            code = product_obj._get_partner_code_name(cr, uid, [], line.product_id, partner_id, context=context)['code']
            if code != line.product_id.default_code:
                res[line.id] = code
            else:
                res[line.id] = ''
        return res

    _columns = {
        'code': fields.function(_product_code, type='char', string='Supplier Reference'),
        'row_color': fields.char(string='Row color'),
        'new_prodlot_code': fields.function(_get_prodlot_code, fnct_inv=_set_prodlot_code,
                                            method=True, type='char', size=64,
                                            string='Prodlot fast input', select=1
                                            ),
        'split_type': fields.related('product_id', 'lot_split_type', type="selection", selection=LOT_SPLIT_TYPE_SELECTION, string="Split", store=False),
        'tracking_id': fields.many2one('stock.tracking', 'Pack/Tracking'),
        'balance': fields.boolean('Balance'),
        'pallet_qty': fields.integer('Number Pallet'),
        'pallet_id': fields.many2one('product.ul', 'Pallet', domain=[('type', '=', 'pallet')]),
        'line_check': fields.boolean('Check'),
    }

    def onchange_new_prodlot_code(self, cr, uid, ids, new_prodlot_code, product_id, prodlot_id, context=None):
        lot_obj = self.pool['stock.production.lot']
        if new_prodlot_code:
            new_prodlot_code = new_prodlot_code.upper()  # all serial number must be on uppercase
        existing_prodlot_ids = lot_obj.search(cr, uid, [('name', '=', new_prodlot_code), ('product_id', '=', product_id)], limit=1, context=context)
        existing_lot = lot_obj.browse(cr, uid, existing_prodlot_ids, context)
        move_type = self.pool['stock.partial.picking.line'].browse(cr, uid, ids, context=context)[0].move_id.picking_id.type
        if existing_lot:
            product = self.pool['product.product'].browse(cr, uid, product_id, context=context)
            if product.lot_split_type == 'single' and move_type != 'out' and existing_lot[0].stock_available > 0:
                return {
                    'warning': {
                        'title': _('Warning!'),
                        'message': (_('Serial number "{number}" is already exists').format(number=new_prodlot_code))
                    }
                }
            else:
                existing_lot_id = existing_prodlot_ids[0]
                return {'value': {'prodlot_id': existing_lot_id}}
        else:
            prodlot_id = self.pool['stock.production.lot'].create(cr, uid, {
                'name': new_prodlot_code,
                'product_id': product_id,
            })
            return {'value': {'prodlot_id': prodlot_id}}
Example #27
0
        cr.execute("SELECT id, state FROM ir_module_module WHERE name='deferred_processing'")
        deferred_proc_module = cr.dictfetchone()
        if deferred_proc_module and deferred_proc_module['state'] in ('installed', 'to upgrade'):
            result.append('deferred_processing')
        ############################################
        return dict.fromkeys(ids, ','.join(result))

    _columns = {
        'charset':fields.selection(_get_encodings, string='Charset', required=True),
        'content_fname': fields.char('Override Extension',size=64, help='Here you can override output file extension'),
        'styles_mode': fields.selection([
            ('default','Not used'),
            ('global', 'Global'),
            ('specified', 'Specified'),
            ], string='Stylesheet'),
        'stylesheet_id':fields.many2one('report.stylesheets', 'Template Stylesheet'),
        'preload_mode':fields.selection([
            ('static',_('Static')),
            ('preload',_('Preload')),
        ],'Preload Mode'),
        'tml_source':fields.selection([
            ('database','Database'),
            ('file','File'),
            ('parser','Parser'),
        ],'Template source', select=True),
        'parser_def': fields.text('Parser Definition'),
        'parser_loc':fields.char('Parser location', size=128, help="Path to the parser location. Beginning of the path must be start with the module name!\nLike this: {module name}/{path to the parser.py file}"),
        'parser_state':fields.selection([
            ('default',_('Default')),
            ('def',_('Definition')),
            ('loc',_('Location')),
Example #28
0
class openacademy_session(osv.Model):
    _name = 'openacademy.session'

    def _check_instructor_not_in_attendees(
        self,
        cr,
        uid,
        ids,
        context=None
    ):  # cuando la fucnion empieza con guion bajo es que es privada, no puedeser usada fuera de open academy
        if not context:
            contex = {}
            print ids, "imprimo ids"
        for session in self.browse(cr, uid, ids, context):
            lista_attendee = []
            for attendee in session.attendee_ids:
                lista_attendee.append(attendee.partner_id.id)
            print lista_attendee, " imprimo lista de attendees"
            if session.instructor_id and session.instructor_id.id in lista_attendee:
                return False
            return True

    def _get_percent(self, seats, attendee_ids):
        try:
            return (100 * len(attendee_ids)) / seats
        except ZeroDivisionError:
            return 0.0

    def _take_seats_percent(self, cr, uid, ids, field, args, context=None):
        print field, "field"
        print args, "args"
        resultado = {}
        for session in self.browse(cr, uid, ids, context):
            resultado[session.id] = self._get_percent(session.seats,
                                                      session.attendee_ids)
        print resultado, "resultado"
        return resultado

    def onchange_taken_seats(self, cr, uid, ids, seats, attendee_ids):
        print attendee_ids, "recibe"
        num_attendees = self.resolve_2many_commands(cr, uid, 'attendee_ids',
                                                    attendee_ids, ['id'])
        print num_attendees, "despues"
        resultado = {
            'value': {
                'taken_seats_percent': self._get_percent(seats, attendee_ids)
            }
        }
        print resultado
        if seats < len(num_attendees):
            resultado['warning'] = {
                'title': "Atencion asientos",
                'message': "No puedes tener menos asientos que asistentes"
            }
        print resultado
        return resultado

    def _determin_end_date(self, cr, uid, ids, field, arg, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context):
            if session.start_date and session.duration:
                start_date = datetime.strptime(session.start_date, "%Y-%m-%d")
                duration = timedelta(days=session.duration - 1)
                end_date = start_date + duration
                res[session.id] = end_date.strftime("%Y-%m-%d")
            else:
                res[session.id] = session.start_date
        print res
        return res

    def _set_end_date(self, cr, uid, id, field, value, arg, context=None):
        session = self.browse(cr, uid, id, context)
        if session.start_date and value:
            start_date = datetime.strptime(session.start_date, "%Y-%m-%d")
            end_date = datetime.strptime(value, "%Y-%m-%d")
            duration = end_date - start_date
            self.write(cr, uid, id, {'duration': duration.days + 1}, context)

    def _determin_hours_from_duration(self,
                                      cr,
                                      uid,
                                      ids,
                                      field,
                                      arg,
                                      context=None):
        result = {}
        sessions = self.browse(cr, uid, ids, context=context)
        for session in sessions:
            result[session.id] = (session.duration *
                                  8 if session.duration else 0)
        return result

    def _set_hours(self, cr, uid, id, field, value, arg, context=None):
        if value:
            self.write(cr, uid, id, {'duration': (value / 8)}, context=context)

    def _get_attendee_count(self, cr, uid, ids, name, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context):
            res[session.id] = len(session.attendee_ids)
        return res

    def action_confirm(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'confirm'}, context=context)

    def action_draft(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'draft'}, context=context)

    def action_done(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'done'}, context=context)

    _columns = {
        'name':
        fields.char(string='Nombre', size=256, required=True),
        'start_date':
        fields.date(string='Fecha Inicio'),
        'duration':
        fields.float(string='Duracion', digits=(6, 2),
                     help='Duracion en dias'),
        'seats':
        fields.integer(string='Numero de asientos'),
        'active':
        fields.boolean(string='Activo'),
        #       'instructor_id': fields.many2one('res.partner', string='Instructor', domain= ['|',('instructor','=',True),('name','ilike','%axel%')] ),
        'instructor_id':
        fields.many2one('res.partner',
                        string='Instructor',
                        domain=[('instructor', '=', True)],
                        required=True),
        'course_id':
        fields.many2one('openacademy.course',
                        string='Curso',
                        ondelete='cascade'),
        'attendee_ids':
        fields.one2many('openacademy.attendee',
                        'session_id',
                        string='Asistentes'),
        'taken_seats_percent':
        fields.function(_take_seats_percent,
                        type='float',
                        string='Taken Seats'),
        'end_date':
        fields.function(_determin_end_date,
                        type='date',
                        string="End Date",
                        fnct_inv=_set_end_date),
        'hours':
        fields.function(_determin_hours_from_duration,
                        type='float',
                        string='Hours',
                        fnct_inv=_set_hours),
        'attendee_count':
        fields.function(_get_attendee_count,
                        type='integer',
                        string='Attendee Count',
                        store=True),
        'color':
        fields.integer('Color'),
        'state':
        fields.selection([('draft', 'Draft'), ('confirm', 'Confirmed'),
                          ('done', 'Done')],
                         string='State'),
    }

    _defaults = {
        'active': True,
        'start_date': fields.date.today,
        'state': 'draft',
    }

    _constraints = [(_check_instructor_not_in_attendees,
                     "El instructor no puede ser asistente",
                     ['instructor_id', 'attendee_ids'])]
                        asset_lines_obj.write(cr, uid, asset_line.get('id'),
                            {'move_check': True, 'move_id': created_id})
                        logging.getLogger(self._name).info("""account.move.line created for {0}""".format(asset_name))
                    except:
                        logging.getLogger('account.asset.asset').error(
                            """ERROR creating the entries of
                            account move from {0}.""".format(__name__))
                        raise orm.except_orm('Error', 'Failure creating the'
                            ' account move lines.')
                else:
                    logging.getLogger(self._name).info("Este activo ya esta asentado!")

    _columns = {
        'asset_code': fields.char('Codigo', size=32, required=False, readonly=False),
        'category_id': fields.many2one('account.asset.category', 'Asset Category', required=True,
                                       change_default=True, readonly=True, states={'draft':[('readonly',False)]},
                                       domain=[('type','=','normal')]),
        'category_parent_id': fields.many2one("account.asset.category", string="Categoria Padre del Activo",
                                              required=False, readonly=True, states={'draft':[('readonly',False)]},
                                              domain=[('type','=','view')] ),
        'account_analytic_id': fields.many2one("account.analytic.account", string="Cuenta analitica",
                                               required=True, domain=[('type','=','normal')]),
        'asset_move_ids': fields.one2many('account.asset.move', 'asset_id','Movimientos'),

        #'asset_move_ids': fields.one2many('account.asset.move', 'asset_id', 'Movements')
    }

    _defaults = {
        'asset_code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'asset.number')
    }
Example #30
0
class account_voucher(osv.osv):
    _inherit = 'account.voucher'

    #set the account for the selected partner
    def onchange_od_partner_id(self, cr, uid, ids, partner_id, context=None):
        res = {}
        if partner_id:
            partner = self.pool.get('res.partner').browse(cr, uid, partner_id)
#            print "###############",partner
#            writeoff_acc_id = partner.
#            return {'value': {'writeoff_acc_id': writeoff_acc_id}}
        return res

    def onchange_od_group_pay(self, cr, uid, ids, od_group_pay, context=None):
        return {'value': {'partner_id': ''}}

    _columns = {
        'od_partner_id':
        fields.many2one('res.partner', 'Partner'),
        'od_populate':
        fields.selection([('dr', 'Debit'), ('cr', 'Credit')], 'Allocation'),
        'od_group_pay':
        fields.boolean('Pay as Group',
                       readonly=True,
                       states={'draft': [('readonly', False)]}),
        'od_payee':
        fields.char('Payee',
                    readonly=True,
                    states={'draft': [('readonly', False)]}),
        'od_acc_payee':
        fields.boolean('A/c Payee',
                       readonly=True,
                       states={'draft': [('readonly', False)]})
    }

    #partner selection in diff amount writeoff
    def writeoff_move_line_get(self,
                               cr,
                               uid,
                               voucher_id,
                               line_total,
                               move_id,
                               name,
                               company_currency,
                               current_currency,
                               context=None):

        move_line = super(account_voucher,
                          self).writeoff_move_line_get(cr,
                                                       uid,
                                                       voucher_id,
                                                       line_total,
                                                       move_id,
                                                       name,
                                                       company_currency,
                                                       current_currency,
                                                       context=None)

        voucher = self.pool.get('account.voucher').browse(
            cr, uid, voucher_id, context)
        if voucher.state == 'draft' and voucher.pdc_check and voucher.od_with_out_allocaion:
            #            partner_rec_acc_id = voucher.partner_id.property_account_receivable.id
            #            partner_payable_acc_id = voucher.partner_id.property_account_payable.id
            mvl_acc_id = move_line.get('account_id')
            #            if mvl_acc_id and mvl_acc_id == partner_rec_acc_id:
            move_line[
                'account_id'] = voucher.od_check_clearing_acc_id and voucher.od_check_clearing_acc_id.id or move_line.get(
                    'account_id')

        if voucher.od_partner_id and voucher.od_partner_id.id:
            move_line[
                'partner_id'] = voucher.od_partner_id and voucher.od_partner_id.id
        return move_line

    def od_deallocate(self, cr, uid, ids, context=None):
        ctx = context.copy()
        for voucher in self.browse(cr, uid, ids, context):

            voucher.line_cr_ids.unlink()
            voucher.line_dr_ids.unlink()
            voucher_cr_lines = []
            voucher_dr_lines = []

            partner_id = voucher.partner_id and voucher.partner_id.id
            journal_id = voucher.journal_id and voucher.journal_id.id
            price = voucher.amount or 0.0
            currency_id = voucher.currency_id and voucher.currency_id.id
            ttype = voucher.type
            rate = voucher.payment_rate
            date = voucher.date
            ctx.update({'date': date})

            payment_rate_currency_id = voucher.payment_rate_currency_id and voucher.payment_rate_currency_id.id

            voucher_rate = self.pool.get('res.currency').read(
                cr, uid, [currency_id], ['rate'], context=ctx)[0]['rate']
            ctx.update({
                'voucher_special_currency': payment_rate_currency_id,
                'voucher_special_currency_rate': rate * voucher_rate,
            })
            res = self.od_recompute_voucher_lines(cr,
                                                  uid,
                                                  ids,
                                                  partner_id,
                                                  journal_id,
                                                  price,
                                                  currency_id,
                                                  ttype,
                                                  date,
                                                  context=ctx)
            cr_lines = res['value'].get('line_cr_ids')
            dr_lines = res['value'].get('line_dr_ids')

            #            if cr_lines and voucher.od_populate == 'cr':
            #                for line in cr_lines:
            #                    voucher_cr_lines.append([0,0,line])
            #            elif dr_lines and voucher.od_populate == 'dr':
            #                for line in dr_lines:
            #                    voucher_dr_lines.append([0,0,line])
            #            else:
            for line in cr_lines:
                voucher_cr_lines.append([0, 0, line])
            for line in dr_lines:
                voucher_dr_lines.append([0, 0, line])

            voucher.write({
                'line_cr_ids': voucher_cr_lines,
                'line_dr_ids': voucher_dr_lines
            })

            print "!!!!!!!~~~~~~~**", res
            return res

        return self.od_recompute_voucher_lines(cr,
                                               uid,
                                               ids,
                                               partner_id,
                                               journal_id,
                                               price,
                                               currency_id,
                                               ttype,
                                               date,
                                               context=ctx)

#    to avoid automatic Allocation

    def recompute_voucher_lines(self,
                                cr,
                                uid,
                                ids,
                                partner_id,
                                journal_id,
                                price,
                                currency_id,
                                ttype,
                                date,
                                context=None):
        #set default values
        default = {
            'value': {
                'line_dr_ids': [],
                'line_cr_ids': [],
                'pre_line': False
            },
        }
        return default

#automatic alocation is overide to allocate manually

    def od_recompute_voucher_lines(self,
                                   cr,
                                   uid,
                                   ids,
                                   partner_id,
                                   journal_id,
                                   price,
                                   currency_id,
                                   ttype,
                                   date,
                                   context=None):
        if context is None:
            context = {}
        if context.get('od_manual_allocate'):
            return {}
        """
        Returns a dict that contains new values and context

        @param partner_id: latest value from user input for field partner_id
        @param args: other arguments
        @param context: context arguments, like lang, time zone

        @return: Returns a dict which contains new values, and context
        """
        def _remove_noise_in_o2m():
            """if the line is partially reconciled, then we must pay attention to display it only once and
                in the good o2m.
                This function returns True if the line is considered as noise and should not be displayed
            """
            if line.reconcile_partial_id:
                if currency_id == line.currency_id.id:
                    if line.amount_residual_currency <= 0:
                        return True
                else:
                    if line.amount_residual <= 0:
                        return True
            return False

        if context is None:
            context = {}
        context_multi_currency = context.copy()

        currency_pool = self.pool.get('res.currency')
        move_line_pool = self.pool.get('account.move.line')
        partner_pool = self.pool.get('res.partner')
        journal_pool = self.pool.get('account.journal')
        line_pool = self.pool.get('account.voucher.line')

        #set default values
        default = {
            'value': {
                'line_dr_ids': [],
                'line_cr_ids': [],
                'pre_line': False
            },
        }

        # drop existing lines
        line_ids = ids and line_pool.search(cr, uid,
                                            [('voucher_id', '=', ids[0])])
        for line in line_pool.browse(cr, uid, line_ids, context=context):
            if line.type == 'cr':
                default['value']['line_cr_ids'].append((2, line.id))
            else:
                default['value']['line_dr_ids'].append((2, line.id))

        if not partner_id or not journal_id:
            return default

        journal = journal_pool.browse(cr, uid, journal_id, context=context)
        partner = partner_pool.browse(cr, uid, partner_id, context=context)
        currency_id = currency_id or journal.company_id.currency_id.id

        total_credit = 0.0
        total_debit = 0.0
        account_type = None
        if context.get('account_id'):
            account_type = self.pool['account.account'].browse(
                cr, uid, context['account_id'], context=context).type
        if ttype == 'payment':
            if not account_type:
                account_type = 'payable'
            total_debit = price or 0.0
        else:
            total_credit = price or 0.0
            if not account_type:
                account_type = 'receivable'


##Custom Code
        move_search_domain = [('state', '=', 'valid'),
                              ('account_id.type', '=', account_type),
                              ('reconcile_id', '=', False),
                              ('partner_id', '=', partner_id)]
        if context.get('od_group_pay'):
            move_search_domain = [('state', '=', 'valid'),
                                  ('account_id.type', '=', account_type),
                                  ('reconcile_id', '=', False),
                                  ('partner_id', 'child_of', partner_id)]

        if not context.get('move_line_ids', False):
            ids = move_line_pool.search(cr,
                                        uid,
                                        move_search_domain,
                                        context=context)
        else:
            ids = context['move_line_ids']
        invoice_id = context.get('invoice_id', False)
        company_currency = journal.company_id.currency_id.id
        move_lines_found = []

        #order the lines by most old first
        ids.reverse()
        account_move_lines = move_line_pool.browse(cr,
                                                   uid,
                                                   ids,
                                                   context=context)

        #compute the total debit/credit and look for a matching open amount or invoice
        for line in account_move_lines:
            if _remove_noise_in_o2m():
                continue

            if invoice_id:
                if line.invoice.id == invoice_id:
                    #if the invoice linked to the voucher line is equal to the invoice_id in context
                    #then we assign the amount on that line, whatever the other voucher lines
                    move_lines_found.append(line.id)
            elif currency_id == company_currency:
                #otherwise treatments is the same but with other field names
                if line.amount_residual == price:
                    #if the amount residual is equal the amount voucher, we assign it to that voucher
                    #line, whatever the other voucher lines
                    move_lines_found.append(line.id)
                    break
                #otherwise we will split the voucher amount on each line (by most old first)
                total_credit += line.credit or 0.0
                total_debit += line.debit or 0.0
            elif currency_id == line.currency_id.id:
                if line.amount_residual_currency == price:
                    move_lines_found.append(line.id)
                    break
                total_credit += line.credit and line.amount_currency or 0.0
                total_debit += line.debit and line.amount_currency or 0.0

        remaining_amount = price
        #voucher line creation
        for line in account_move_lines:

            if _remove_noise_in_o2m():
                continue

            if line.currency_id and currency_id == line.currency_id.id:
                amount_original = abs(line.amount_currency)
                amount_unreconciled = abs(line.amount_residual_currency)
            else:
                #always use the amount booked in the company currency as the basis of the conversion into the voucher currency
                amount_original = currency_pool.compute(
                    cr,
                    uid,
                    company_currency,
                    currency_id,
                    line.credit or line.debit or 0.0,
                    context=context_multi_currency)
                amount_unreconciled = currency_pool.compute(
                    cr,
                    uid,
                    company_currency,
                    currency_id,
                    abs(line.amount_residual),
                    context=context_multi_currency)
            line_currency_id = line.currency_id and line.currency_id.id or company_currency
            rs = {
                'name': line.move_id.name,
                'type': line.credit and 'dr' or 'cr',
                'move_line_id': line.id,
                'account_id': line.account_id.id,
                'amount_original': amount_original,
                'amount': 0.0,  #custom
                'date_original': line.date,
                'date_due': line.date_maturity,
                'amount_unreconciled': amount_unreconciled,
                'currency_id': line_currency_id,
                'od_partner_id': line.partner_id
                and line.partner_id.id,  #Custom Code
            }
            remaining_amount -= rs['amount']
            #in case a corresponding move_line hasn't been found, we now try to assign the voucher amount
            #on existing invoices: we split voucher amount by most old first, but only for lines in the same currency
            if not move_lines_found:
                if currency_id == line_currency_id:
                    if line.credit:
                        amount = min(amount_unreconciled, abs(total_debit))
                        rs['amount'] = 0.0
                        total_debit -= amount
                    else:
                        amount = min(amount_unreconciled, abs(total_credit))
                        rs['amount'] = 0.0
                        total_credit -= amount

            if rs['amount_unreconciled'] == rs['amount']:
                rs['reconcile'] = True

            if rs['type'] == 'cr':
                default['value']['line_cr_ids'].append(rs)
            else:
                default['value']['line_dr_ids'].append(rs)

            if len(default['value']['line_cr_ids']) > 0:
                default['value']['pre_line'] = 1
            elif len(default['value']['line_dr_ids']) > 0:
                default['value']['pre_line'] = 1
            default['value'][
                'writeoff_amount'] = self._compute_writeoff_amount(
                    cr, uid, default['value']['line_dr_ids'],
                    default['value']['line_cr_ids'], price, ttype)
        return default
# -*- coding: utf-8 -*-
from openerp.osv import fields, orm
import datetime

class manuscrito(orm.Model):
	_name = 'res.manuscrito'
	_description = 'Manuscrito'
	_columns = {
		'autor': fields.many2one('res.partner', 'Autor', track_visibility='onchange',required=True, select=True),domain="[('author','=',True)]"),
		'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null', track_visibility='onchange',
            select=True, help="Linked partner (optional). Usually created when converting the lead."),

		'titulo': fields.char('Título', size=50, required=True),
		'isbn':fields.char('ISBN', size=30, required=True),
		'formato':fields.char('Formato', size=30),
		'genero':fields.selection([('ciencia-ficcion','Ciencia-Ficcion'),('novela','Novela'),('poesia','Poesía'),('cuento','Cuento'),('historia','Historia'),('miedo','Miedo'),('otro','Otros')],'Género', required=True),
		'email':fields.char('E-MAIL',size=20),
		'comment': fields.text('Descripción'),
		'image': fields.binary("Image", help="Select image here"),
		'date': fields.date('Date', select=1),
		'idioma':fields.selection([('cas','Castellano'),('en','Inglés'),('fr','Francés')],'Idioma'),
		'state': fields.selection([('recibo', 'Acuse recibo'),('eval', 'Evaluación'),('confirmacion','Pendiente confirmación'),('cancelled', 'Cancelado'),('firma', 'Firma Contrato'),('corregir', 'Corrección'),('reenvio', 'Visto bueno autor'),('envio imprenta', 'Enviado a imprenta'), ('done', 'Hecho')]),
	}
	def set_recibo(self, cr, uid, ids, context=None):
		return self.write(cr, uid, ids, {'state': 'eval'}, context=context)
	def set_evaluar(self, cr, uid, ids, context=None):
		return self.write(cr, uid, ids, {'state': 'confirmacion'}, context=context)
	def set_aceptar(self, cr, uid, ids, context=None):
		return self.write(cr, uid, ids, {'state': 'firma'}, context=context)
	def set_firmar(self, cr, uid, ids, context=None):
		return self.write(cr, uid, ids, {'state': 'corregir'}, context=context)
Example #32
0
class account_voucher_line(osv.osv):
    _inherit = 'account.voucher.line'
    _columns = {
        'od_partner_id': fields.many2one('res.partner', 'Partner'),
    }
    def _setup_analytic_fields(cls, analytic, para, columns, defaults, orm_name, name, bases, nmspc):
        """Generate analytic and para-analytic fields on the model."""

        # If _analytic uses a shortcut, convert it into a prefix-model mapping.
        if analytic is True:
            analytic = {"a": orm_name.replace(".", "_")}
        elif isinstance(analytic, basestring):
            analytic = {"a": analytic}

        # Create a field that will be used for replacement in the view
        if analytic:
            columns["analytic_dimensions"] = fields.function(
                lambda self, cr, uid, ids, *a: {i: "" for i in ids},
                string=u"Analytic Dimensions",
                readonly=True,
                store=False,
            )

        col_pattern = "{pre}{n}_{suf}"
        size = int(config.get_misc("analytic", "analytic_size", 5))

        # Generate the fields directly into the _columns attribute.
        all_analytic = []

        for prefix, model_name in analytic.iteritems():
            # Analytic fields
            all_analytic.append((model_name, prefix, "id"))

            for n in xrange(1, size + 1):
                col_name = col_pattern.format(pre=prefix, n=n, suf="id")
                domain_field = "nd_id.ns{n}_id.model_name".format(n=n)
                columns[col_name] = fields.many2one(
                    "analytic.code",
                    "Generated Analytic Field",
                    domain=[
                        (domain_field, "=", model_name),
                        ("view_type", "=", False),
                        ("disabled_per_company", "=", False),
                    ],
                    track_visibility="onchange",
                )

        for key, value in para.iteritems():
            # Para-analytic fields
            prefix, suffix = key
            model_name = value["model"]
            all_analytic.append((model_name, prefix, suffix))
            if suffix == "id":
                raise ValueError("Para-analytic suffix cannot be 'id'")

            field_type = value["type"]
            args = value["args"]
            kwargs = value["kwargs"]
            for n in xrange(1, size + 1):
                col_name = col_pattern.format(pre=prefix, n=n, suf=suffix)
                columns[col_name] = field_type(*args, **kwargs)
                if "default" in value:
                    defaults[col_name] = value["default"]

        # In order to preserve inheritance, possible overrides, and OEMetaSL's
        # expected behavior, work on a new class that inherits the given bases,
        # then make our model class inherit from this class.
        superclass_name = "_{name}_SuperAnalytic".format(name=name)
        # Set _register to False in order to prevent its instantiation.
        superclass = type(superclass_name, bases, {"_register": False})

        @AddMethod(superclass)
        def fields_get(self, cr, uid, allfields=None, context=None, write_access=True):
            """Override this method to rename analytic fields."""

            res = super(superclass, self).fields_get(
                cr, uid, allfields=allfields, context=context, write_access=write_access
            )

            analytic_osv = self.pool.get("analytic.structure")

            for model_name, prefix, suffix in all_analytic:
                res = analytic_osv.analytic_fields_get(cr, uid, model_name, res, prefix, suffix, context=context)

            return res

        @AddMethod(superclass)
        def fields_view_get(self, cr, uid, view_id=None, view_type="form", context=None, toolbar=False, submenu=False):
            """Override this method to hide unused analytic fields."""

            res = super(superclass, self).fields_view_get(
                cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu
            )

            analytic_osv = self.pool.get("analytic.structure")

            for model_name, prefix, suffix in all_analytic:
                res = analytic_osv.analytic_fields_view_get(cr, uid, model_name, res, prefix, suffix, context=context)

            return res

        return (superclass,)
Example #34
0
class MailMessage(osv.Model):
    _name = "sale.comment"
    _description = "Sale Comment"

    _columns = {
        'comment_date':
        fields.datetime('Comment Date'),
        'seller_reply_date':
        fields.datetime('Seller Reply Date'),
        'chase_comment_date':
        fields.datetime('Chase Comment Date'),
        'comment_body':
        fields.html('Comment Contents',
                    help='Automatically sanitized HTML contents'),
        'seller_reply_body':
        fields.html('Seller Reply Contents',
                    help='Automatically sanitized HTML contents'),
        'chase_comment_body':
        fields.html('Chase Comment Contents',
                    help='Automatically sanitized HTML contents'),
        'rating':
        fields.integer("Rating"),
        'order_id':
        fields.many2one('sale.order', "Related Sale Order ID"),
        'order_line_id':
        fields.many2one('sale.order.line', "Related Sale Order Line ID"),
        'author_id':
        fields.many2one('res.partner', 'Author',
                        help="Author of the comment."),
        'product_tmp_id':
        fields.many2one('product.template', "Related Product Template ID"),
        'website_published':
        fields.boolean(
            'Published',
            help="Visible on the website as a comment",
            copy=False,
        ),
        'is_anonymous':
        fields.boolean('Is Anonymous', default=False),
        'wait_business_reply':
        fields.boolean('Wait for the business reply', default=True),
    }

    def _prepare_comment(self, cr, uid, line_id, context=None):
        line_obj = self.pool.get('sale.order.line')
        if context is None:
            context = {}
        description = context.get('description')
        rating = context.get('rating')
        website_published = context.get('website_published')
        is_anonymous = context.get('is_anonymous')

        values = {}
        for line in line_obj.browse(cr, uid, line_id, context=context):
            values['comment_date'] = time.strftime("%Y-%m-%d %H:%M:%S")
            values['comment_body'] = description
            values['rating'] = rating
            values['order_id'] = line.order_id.id
            values['order_line_id'] = line.id
            values['author_id'] = line.order_partner_id.id
            values['product_tmp_id'] = line.product_id.product_tmpl_id.id
            values['website_published'] = website_published
            values['is_anonymous'] = is_anonymous
            values['wait_business_reply'] = True
        return values

    def create_comment(self, cr, uid, line_id, context=None):
        """Create the comment by those values

            :param line_id: sale order line ID(int)
        """
        if context is None:
            context = {}
        value = self._prepare_comment(cr, uid, line_id, context=context)
        comm_ids = self.create(cr, uid, value, context=context)

        return comm_ids
Example #35
0
		for this in self.browse(cr, uid, ids, context=context):
			res[this.id] = this.invoice_lines and \
				all(iline.invoice_id.state != 'cancel' for iline in this.invoice_lines) 
		return res

	def _order_lines_from_invoice(self, cr, uid, ids, context=None):
		# direct access to the m2m table is the less convoluted way to achieve this (and is ok ACL-wise)
		cr.execute("""SELECT DISTINCT sol.id FROM sale_order_invoice_rel rel JOIN
												  sale_order_line sol ON (sol.order_id = rel.order_id)
									WHERE rel.invoice_id = ANY(%s)""", (list(ids),))
		return [i[0] for i in cr.fetchall()]

	_name = 'sale.order.line'
	_description = 'Sales Order Line'
	_columns = {
		'order_id': fields.many2one('sale.order', 'Order Reference', required=True, ondelete='cascade', select=True, readonly=True, states={'draft':[('readonly',False)]}),
		'name': fields.text('Description', required=True, readonly=True, states={'draft': [('readonly', False)]}),
		'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of sales order lines."),
		'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True),
		'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True),
		'invoiced': fields.function(_fnct_line_invoiced, string='Invoiced', type='boolean',
			store={
				'account.invoice': (_order_lines_from_invoice, ['state'], 10),
				'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10)}),
		'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}),
		'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]},
		 help="From stock: When needed, the product is taken from the stock or we wait for replenishment.\nOn order: When needed, the product is purchased or produced."),
		'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')),
		'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}),
		'address_allotment_id': fields.many2one('res.partner', 'Allotment Partner',help="A partner to whom the particular product needs to be allotted."),
		'product_uom_qty': fields.float('Quantity', digits_compute= dp.get_precision('Product UoS'), required=True, readonly=True, states={'draft': [('readonly', False)]}),
Example #36
0
class generate_pr_wizard(osv.osv_memory):
    _name = 'generate.pr.wizard'
    _description = 'Generate PR Wizard'
    _columns = {
        'delivery_date': fields.date('Delivery Date', required=True),
        'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', required=True),
    }

    def _get_bom_line(self, cr, uid, order_line):
        return {
            'item_no': order_line.item_no,
            'part_name': order_line.name,
            'description': order_line.description,
            'erp_no': order_line.erp_no,
            'standard': order_line.standard,
            'material': order_line.material,
            'thickness': order_line.thickness,
            'work_steps': order_line.work_steps,
            'part_type': order_line.part_type,
            'bom_qty': order_line.bom_qty,
            'quantity': getattr(order_line,
                                    "%s_need_qty" % order_line.last_step, 0),
            'product_id': order_line.product_id,
        }

    def _create_pr(self, cr, uid, pr_vals):
        pur_req_obj = self.pool.get('pur.req')
        return pur_req_obj.create(cr, uid, pr_vals)

    def _create_pr_line(self, cr, uid, pr_id, bom_line, sequence, delivery_date, drawing_order_id = False,):
        pr_line_obj = self.pool.get('pur.req.line')
        po_line_obj = self.pool.get('purchase.order.line')
        if bom_line['part_type'] != 'PRODUCED':
            product = bom_line['product_id']
            uom = product.uom_id or product.uom_po_id
            pur_req_line_vals = {
                'product_id': product.id,
                'product_uom_id': uom.id,
                'uom_categ_id': product.uom_id.category_id.id,
                'date_required': delivery_date,
                'inv_qty': product.qty_available,
                'req_id': pr_id,
            }
            if drawing_order_id:
                pur_req_line_vals.update({'drawing_order_id': drawing_order_id,})
            #Check if this product already in pr lines
            exist_pr_line_ids = pr_line_obj.search(cr, uid, [
                ('req_id','=',pr_id),
                ('product_id','=',product.id),
            ])
            quantity = bom_line['quantity']
            if exist_pr_line_ids:
                pr_line = pr_line_obj.browse(cr, uid, exist_pr_line_ids[0])
                quantity += pr_line.product_qty
                need_to_order = 0
                if quantity > product.qty_available:
                    need_to_order = quantity - product.qty_available
                pr_line_obj.write(cr, uid, [pr_line.id],{
                    'product_qty' : quantity,
                    'need_order_quantity': need_to_order,
                })
            else:
                need_to_order = 0
                if quantity > product.qty_available:
                    need_to_order = quantity - product.qty_available
                pur_req_line_vals.update({
                    'product_qty': quantity,
                    'sequence': sequence,
                    'erp_no': bom_line['erp_no'],
                    'item_no': bom_line['item_no'],
                    'name': bom_line["description"],
                    'material': bom_line["material"],
                    'standard': bom_line["standard"],
                    'quantity_per_unit': bom_line["bom_qty"],
                    'inv_qty': product.qty_available,
                    'reserved_quantity': 0,
                    'need_order_quantity': need_to_order,
                    'note': '',
                    'price': product.uom_po_price,
                })
                purchase_order_line_ids = po_line_obj.search(cr, uid,
                                                                         [('product_id', '=', product.id),
                                                                          ('state', 'in',
                                                                           ['confirmed', 'approved',
                                                                            'done'])],
                                                                         order="date_planned desc")
                if purchase_order_line_ids:
                    purchase_order_line = po_line_obj.browse(cr, uid, purchase_order_line_ids)[
                        0]
                    pur_req_line_vals.update({'supplier_id': purchase_order_line.order_id.partner_id.id})
                pr_line_obj.create(cr, uid, pur_req_line_vals)
        return True

    def do_generate(self, cr, uid, ids, context=None):
        generate_pr = self.browse(cr, uid, ids, context)[0]
        drawing_order_ids = context.get('drawing_order_ids', False)
        drawing_order_obj = self.pool.get('drawing.order')
        pur_req_obj = self.pool.get('pur.req')
        if drawing_order_ids:
            pr_names = []
            for order in drawing_order_obj.browse(cr, uid, drawing_order_ids):
                pur_req_ids = pur_req_obj.search(cr, uid, [
                    ('drawing_order_id', '=', order.id)
                ])
                if pur_req_ids:
                    raise osv.except_osv(_("Error!"),
                                         _('A Purchase Requisition of this drawing order is already exist!'))
                pur_req_id = self._create_pr(cr, uid, {
                    'warehouse_id': generate_pr.warehouse_id.id,
                    'drawing_order_id': order.id,
                    'pr_type': 'mfg',
                    'unit': order.product_id.id,
                    'delivery_date': generate_pr.delivery_date,
                    'engineer': uid,
                })
                pr = pur_req_obj.browse(cr, uid, pur_req_id)
                pr_names.append(pr.name)
                sequence = 1
                for order_line in order.order_lines:
                    bom_line = self._get_bom_line(cr, uid, order_line)
                    self._create_pr_line(cr, uid, pur_req_id,bom_line,sequence,generate_pr.delivery_date,order.id)
                    sequence += 1
            return self.pool.get('warning').info(cr, uid, title='Information', message=_(
                "PR [%s] has been created!")% ",".join(pr_names) )
        return True
Example #37
0
                else :
                    res[user1.id] = user1.server.server_addres +':' + user1.server.rpc_port+'/web?db='+ user1.host_name.lower()
        return res

    def get_counter(self,cr,uid,context=None):
        myids = self.search(cr, uid, [], context=context)
        for user in self.browse(cr,uid,myids,context=context):
            res = user.counter +1;
            isTrue =   self.write(cr, uid, user.id, {'counter': res}, context=context)
        return isTrue

    _name = "saas.user.info"
    _description = "saas.user.info"
    _columns = {
        'name': fields.char('Note', required=False,track_visibility='always', help=""),
        'user': fields.many2one('res.partner', 'partner', help=""),
        'host_name': fields.char('host_name',required=True, help=""),
        'host_type': fields.char('host_type',required=False , help=""),
        'server': fields.many2one('saas.server', 'server',required=True, help=""),
        'url_addres': fields.function(_get_full_url, type='char',string='url_addres'),
        'start_date': fields.datetime('start_date',required=False, help=""),
        'end_date': fields.function(_compute_exp_date, type = 'datetime',string='end_date'),
        'product_id':fields.many2one('product.product','product_id',required = False,help=''),
        'state': fields.function(_get_server_state, type='char', string='state'),
        'counter': fields.integer('counter',required=False , help=""),
    }
    _defaults = {
        'start_date': fields.datetime.now,
    }
    _sql_constraints = [
        ('host_name_uniq', 'unique (host_name)', 'host_name must be unique !'),
Example #38
0
class product_template(Model):
    _inherit = "product.template"

    _columns = {
        'attribute_set_id': fields.many2one('attribute.set', 'Attribute Set'),
    }
Example #39
0
        try:
            proxy = self.pool.get("ir.model.data")
            result = proxy.get_object_reference(cr, uid, "product", "product_uom_unit")
            return result[1]
        except Exception, ex:
            return False

    _name = "rent.order.line"
    _description = "Rent Order Line"
    _columns = {
        "name": fields.text("Description", required=True, readonly=True, states={"draft": [("readonly", False)]}),
        "order_id": fields.many2one(
            "rent.order",
            "Rent Reference",
            required=True,
            ondelete="cascade",
            select=True,
            readonly=True,
            states={"draft": [("readonly", False)]},
        ),
        "sequence": fields.integer("Sequence"),
        "product_id": fields.many2one(
            "product.product", "Product", domain=[("is_rent", "=", True)], change_default=True
        ),
        "invoice_lines": fields.many2many(
            "account.invoice.line",
            "rent_order_line_invoice_rel",
            "order_line_id",
            "invoice_id",
            "Invoice Lines",
            readonly=True,
class crm_phonecall2phonecall(osv.osv_memory):
    _name = 'crm.phonecall2phonecall'
    _description = 'Phonecall To Phonecall'

    _columns = {
        'name' : fields.char('Call summary', required=True, select=1),
        'user_id' : fields.many2one('res.users',"Assign To"),
        'contact_name':fields.char('Contact'),
        'phone':fields.char('Phone'),
        'categ_id': fields.many2one('crm.case.categ', 'Category', \
                domain="['|',('team_id','=',False),('team_id','=',team_id),\
                ('object_id.model', '=', 'crm.phonecall')]"), 
        'date': fields.datetime('Date'),
        'team_id':fields.many2one('crm.case.section','Sales Team'),
        'action': fields.selection([('schedule','Schedule a call'), ('log','Log a call')], 'Action', required=True),
        'partner_id' : fields.many2one('res.partner', "Partner"),
        'note':fields.text('Note')
    }


    def action_cancel(self, cr, uid, ids, context=None):
        """
        Closes Phonecall to Phonecall form
        """
        return {'type':'ir.actions.act_window_close'}

    def action_schedule(self, cr, uid, ids, context=None):
        value = {}
        if context is None:
            context = {}
        phonecall = self.pool.get('crm.phonecall')
        phonecall_ids = context and context.get('active_ids') or []
        for this in self.browse(cr, uid, ids, context=context):
            phocall_ids = phonecall.schedule_another_phonecall(cr, uid, phonecall_ids, this.date, this.name, \
                    this.user_id and this.user_id.id or False, \
                    this.team_id and this.team_id.id or False, \
                    this.categ_id and this.categ_id.id or False, \
                    action=this.action, context=context)

        return phonecall.redirect_phonecall_view(cr, uid, phocall_ids[phonecall_ids[0]], context=context)
    
    def default_get(self, cr, uid, fields, context=None):
        """
        This function gets default values
        
        """
        res = super(crm_phonecall2phonecall, self).default_get(cr, uid, fields, context=context)
        record_id = context and context.get('active_id', False) or False
        res.update({'action': 'schedule', 'date': time.strftime('%Y-%m-%d %H:%M:%S')})
        if record_id:
            phonecall = self.pool.get('crm.phonecall').browse(cr, uid, record_id, context=context)

            categ_id = False
            data_obj = self.pool.get('ir.model.data')
            try:
                res_id = data_obj._get_id(cr, uid, 'crm', 'categ_phone2')
                categ_id = data_obj.browse(cr, uid, res_id, context=context).res_id
            except ValueError:
                pass

            if 'name' in fields:
                res.update({'name': phonecall.name})
            if 'user_id' in fields:
                res.update({'user_id': phonecall.user_id and phonecall.user_id.id or False})
            if 'date' in fields:
                res.update({'date': False})
            if 'team_id' in fields:
                res.update({'team_id': phonecall.team_id and phonecall.team_id.id or False})
            if 'categ_id' in fields:
                res.update({'categ_id': categ_id})
            if 'partner_id' in fields:
                res.update({'partner_id': phonecall.partner_id and phonecall.partner_id.id or False})
        return res
        'type': fields.selection([
            ('payable','Payable'),
            ('receivable','Receivable'),
            ],'Type', readonly=True, select=True),
        # invisible field to filter payment order lines by payment type
        'payment_type_name': fields.function(_payment_type_name_get, method=True, type="char", size=64, string="Payment type name"),
        # The field name is necessary to add attachement documents to payment orders
        'name': fields.function(_name_get, method=True, type="char", size=64, string="Name"),
        'create_account_moves': fields.selection([('bank-statement','Bank Statement'),('direct-payment','Direct Payment')],
                                                 'Create Account Moves',
                                                 required=True,
                                                 states={'done':[('readonly',True)]},
                                                 help='Indicates when account moves should be created for order payment lines. "Bank Statement" '\
                                                      'will wait until user introduces those payments in bank a bank statement. "Direct Payment" '\
                                                      'will mark all payment lines as payied once the order is done.'),
        'period_id': fields.many2one('account.period', 'Period', states={'done':[('readonly',True)]}),
    }
    _defaults = {
        'type': _get_type,
        'reference': _get_reference,
        'create_account_moves': lambda *a: 'bank-statement',
        'period_id': _get_period,
    }

    def cancel_from_done(self, cr, uid, ids, context=None):
        if context is None:
            context = {}

        #Search for account_moves
        remove = []
        for move in self.browse(cr,uid,ids,context):
class ResCompany(orm.Model):
    _inherit = 'res.company'

    _columns = {
        'colipostefr_account': fields.char(
            'Compte Principal',
            size=6,
            help=u"Nombre à 6 caractères.\n"
                 u"La valeur par défaut est 964744"),
        'colipostefr_world_account': fields.char(
            'Compte International',
            size=6,
            help=u"Nombre à 6 caractères.\n"
                 u"La valeur par défaut est 964744\n"
                 u"Potentiellement c'est le même N° que le compte principal."
                 u"Dans ce cas, vous pouvez laisser ce champ vide."),
        'colipostefr_support_city': fields.char(
            'Site de Prise en Charge',
            size=64,
            help="Site de prise en charge de la poste pour son client.\n"
                 "Indiquer votre propre centre de rattachement"),
        'colipostefr_support_city_code': fields.char(
            'Code Site de Prise en Charge',
            size=6,
            help="Utile uniquement pour le module colissimo EDI "
                 "(facultatif cependant)"),
        'colipostefr_password': fields.char(
            'mot de passe site web',
            help=u"le mot de passe doit être identique "
                 u"à celui de votre espace client.\n"
                 u"uniquement nécessaire pour les envois à l'étranger.\n"
                 u"mettre un mot de passe complexe"),
        'colipostefr_unittest_helper': fields.boolean(
            'Unit Test Helper',
            help=u"Seulement utile pour les développeurs.\n"
                 u"Si coché enregistre les données du picking ColiPoste\n"
                 u"dans le dossier temporaire système du serveur.\n"
                 u"Ce fichier peut être utilisé pour créer "
                 u"de nouveaux tests unitaires python"),
        'colipostefr_webservice_message': fields.boolean(
            u'Enregistre les Messages du Webservice',
            help=u"Pour ColiPoste International. \nSi coché, un commentaire "
                 u"sera créé dans le bon de livraison\nsi la réponse du "
                 u"web service contient un message additionnel."),
        'colipostefr_repo_task_id': fields.many2one(
            'repository.task',
            string=u"Tâche EDI",
            help=u"Liaison à la tâche qui exporte le fichier EDI.\n"
                 u"Ne pas créer de tâche spécifique ici.\n"
                 u"La valeur par défaut pour la principale société d'Odoo "
                 u"ne doit pas changer.\nUtilisez une tâche créée "
                 u"depuis le repository 'La Poste EDI'\n"
                 u"(Configuration > File Exchange > File Repositories "
                 u"> La Poste EDI)"),
    }

    _defaults = {
        'colipostefr_account': '',
        'colipostefr_support_city': '... PFC',
        'colipostefr_password': '',
        'colipostefr_unittest_helper': False,
        'colipostefr_webservice_message': True,
    }
Example #43
0
            if res[1]:
                user_id = res[0]
        elif conf["create_user"]:
            _logger.debug('Creating new OpenERP user "%s" from LDAP' % login)
            user_obj = self.pool.get("res.users")
            values = self.map_ldap_attributes(cr, uid, conf, login, ldap_entry)
            if conf["user"]:
                user_id = user_obj.copy(cr, SUPERUSER_ID, conf["user"], default={"active": True})
                user_obj.write(cr, SUPERUSER_ID, user_id, values)
            else:
                user_id = user_obj.create(cr, SUPERUSER_ID, values)
        return user_id

    _columns = {
        "sequence": fields.integer("Sequence"),
        "company": fields.many2one("res.company", "Company", required=True, ondelete="cascade"),
        "ldap_server": fields.char("LDAP Server address", size=64, required=True),
        "ldap_server_port": fields.integer("LDAP Server port", required=True),
        "ldap_binddn": fields.char(
            "LDAP binddn",
            size=64,
            help=(
                "The user account on the LDAP server that is used to query "
                "the directory. Leave empty to connect anonymously."
            ),
        ),
        "ldap_password": fields.char(
            "LDAP password",
            size=64,
            help=("The password of the user account on the LDAP server that is " "used to query the directory."),
        ),
Example #44
0
class hr_applicant(osv.Model):
    _name = "hr.applicant"
    _description = "Applicant"
    _order = "id desc"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    _track = {
        'stage_id': {
            # this is only an heuristics; depending on your particular stage configuration it may not match all 'new' stages
            'hr_recruitment.mt_applicant_new':
            lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.
            sequence <= 1,
            'hr_recruitment.mt_applicant_stage_changed':
            lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.
            sequence > 1,
        },
    }
    _mail_mass_mailing = _('Applicants')

    def _get_default_department_id(self, cr, uid, context=None):
        """ Gives default department by checking if present in the context """
        return (self._resolve_department_id_from_context(
            cr, uid, context=context) or False)

    def _get_default_stage_id(self, cr, uid, context=None):
        """ Gives default stage_id """
        department_id = self._get_default_department_id(cr,
                                                        uid,
                                                        context=context)
        return self.stage_find(cr,
                               uid, [],
                               department_id, [('fold', '=', False)],
                               context=context)

    def _resolve_department_id_from_context(self, cr, uid, context=None):
        """ Returns ID of department based on the value of 'default_department_id'
            context key, or None if it cannot be resolved to a single
            department.
        """
        if context is None:
            context = {}
        if type(context.get('default_department_id')) in (int, long):
            return context.get('default_department_id')
        if isinstance(context.get('default_department_id'), basestring):
            department_name = context['default_department_id']
            department_ids = self.pool.get('hr.department').name_search(
                cr, uid, name=department_name, context=context)
            if len(department_ids) == 1:
                return int(department_ids[0][0])
        return None

    def _get_default_company_id(self,
                                cr,
                                uid,
                                department_id=None,
                                context=None):
        company_id = False
        if department_id:
            department = self.pool['hr.department'].browse(cr,
                                                           uid,
                                                           department_id,
                                                           context=context)
            company_id = department.company_id.id if department and department.company_id else False
        if not company_id:
            company_id = self.pool['res.company']._company_default_get(
                cr, uid, 'hr.applicant', context=context)
        return company_id

    def _read_group_stage_ids(self,
                              cr,
                              uid,
                              ids,
                              domain,
                              read_group_order=None,
                              access_rights_uid=None,
                              context=None):
        access_rights_uid = access_rights_uid or uid
        stage_obj = self.pool.get('hr.recruitment.stage')
        order = stage_obj._order
        # lame hack to allow reverting search, should just work in the trivial case
        if read_group_order == 'stage_id desc':
            order = "%s desc" % order
        # retrieve section_id from the context and write the domain
        # - ('id', 'in', 'ids'): add columns that should be present
        # - OR ('department_id', '=', False), ('fold', '=', False): add default columns that are not folded
        # - OR ('department_id', 'in', department_id), ('fold', '=', False) if department_id: add department columns that are not folded
        department_id = self._resolve_department_id_from_context(
            cr, uid, context=context)
        search_domain = []
        if department_id:
            search_domain += ['|', ('department_id', '=', department_id)]
        search_domain += [
            '|', ('id', 'in', ids), ('department_id', '=', False)
        ]
        stage_ids = stage_obj._search(cr,
                                      uid,
                                      search_domain,
                                      order=order,
                                      access_rights_uid=access_rights_uid,
                                      context=context)
        result = stage_obj.name_get(cr,
                                    access_rights_uid,
                                    stage_ids,
                                    context=context)
        # restore order of the search
        result.sort(
            lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))

        fold = {}
        for stage in stage_obj.browse(cr,
                                      access_rights_uid,
                                      stage_ids,
                                      context=context):
            fold[stage.id] = stage.fold or False
        return result, fold

    def _compute_day(self, cr, uid, ids, fields, args, context=None):
        """
        @param cr: the current row, from the database cursor,
        @param uid: the current user’s ID for security checks,
        @param ids: List of Openday’s IDs
        @return: difference between current date and log date
        @param context: A standard dictionary for contextual values
        """
        res = {}
        for issue in self.browse(cr, uid, ids, context=context):
            for field in fields:
                res[issue.id] = {}
                duration = 0
                ans = False
                hours = 0

                if field in ['day_open']:
                    if issue.date_open:
                        date_create = datetime.strptime(
                            issue.create_date, "%Y-%m-%d %H:%M:%S")
                        date_open = datetime.strptime(issue.date_open,
                                                      "%Y-%m-%d %H:%M:%S")
                        ans = date_open - date_create

                elif field in ['day_close']:
                    if issue.date_closed:
                        date_create = datetime.strptime(
                            issue.create_date, "%Y-%m-%d %H:%M:%S")
                        date_close = datetime.strptime(issue.date_closed,
                                                       "%Y-%m-%d %H:%M:%S")
                        ans = date_close - date_create
                if ans:
                    duration = float(ans.days)
                    res[issue.id][field] = abs(float(duration))
        return res

    def _get_attachment_number(self, cr, uid, ids, fields, args, context=None):
        res = dict.fromkeys(ids, 0)
        for app_id in ids:
            res[app_id] = self.pool['ir.attachment'].search_count(
                cr,
                uid, [('res_model', '=', 'hr.applicant'),
                      ('res_id', '=', app_id)],
                context=context)
        return res

    _columns = {
        'name': fields.char('Subject / Application Name', size=128, required=True),
        'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the case without removing it."),
        'description': fields.text('Description'),
        'email_from': fields.char('Email', size=128, help="These people will receive email."),
        'email_cc': fields.text('Watchers Emails', size=252, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
        'probability': fields.float('Probability'),
        'partner_id': fields.many2one('res.partner', 'Contact'),
        'create_date': fields.datetime('Creation Date', readonly=True, select=True),
        'write_date': fields.datetime('Update Date', readonly=True),
        'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage', track_visibility='onchange',
                        domain="['|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
        'last_stage_id': fields.many2one('hr.recruitment.stage', 'Last Stage',
                                         help='Stage of the applicant before being in the current stage. Used for lost cases analysis.'),
        'categ_ids': fields.many2many('hr.applicant_category', string='Tags'),
        'company_id': fields.many2one('res.company', 'Company'),
        'user_id': fields.many2one('res.users', 'Responsible', track_visibility='onchange'),
        'date_closed': fields.datetime('Closed', readonly=True, select=True),
        'date_open': fields.datetime('Assigned', readonly=True, select=True),
        'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
        'date_action': fields.date('Next Action Date'),
        'title_action': fields.char('Next Action', size=64),
        'priority': fields.selection(AVAILABLE_PRIORITIES, 'Appreciation'),
        'job_id': fields.many2one('hr.job', 'Applied Job'),
        'salary_proposed_extra': fields.char('Proposed Salary Extra', size=100, help="Salary Proposed by the Organisation, extra advantages"),
        'salary_expected_extra': fields.char('Expected Salary Extra', size=100, help="Salary Expected by Applicant, extra advantages"),
        'salary_proposed': fields.float('Proposed Salary', help="Salary Proposed by the Organisation"),
        'salary_expected': fields.float('Expected Salary', help="Salary Expected by Applicant"),
        'availability': fields.integer('Availability', help="The number of days in which the applicant will be available to start working"),
        'partner_name': fields.char("Applicant's Name", size=64),
        'partner_phone': fields.char('Phone', size=32),
        'partner_mobile': fields.char('Mobile', size=32),
        'type_id': fields.many2one('hr.recruitment.degree', 'Degree'),
        'department_id': fields.many2one('hr.department', 'Department'),
        'survey': fields.related('job_id', 'survey_id', type='many2one', relation='survey.survey', string='Survey'),
        'response_id': fields.many2one('survey.user_input', "Response", ondelete='set null', oldname="response"),
        'reference': fields.char('Referred By', size=128),
        'source_id': fields.many2one('hr.recruitment.source', 'Source'),
        'day_open': fields.function(_compute_day, string='Days to Open', \
                                multi='day_open', type="float", store=True),
        'day_close': fields.function(_compute_day, string='Days to Close', \
                                multi='day_close', type="float", store=True),
        'color': fields.integer('Color Index'),
        'emp_id': fields.many2one('hr.employee', string='Employee', help='Employee linked to the applicant.'),
        'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
        'attachment_number': fields.function(_get_attachment_number, string='Number of Attachments', type="integer"),
    }

    _defaults = {
        'active':
        lambda *a: 1,
        'user_id':
        lambda s, cr, uid, c: uid,
        'stage_id':
        lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
        'department_id':
        lambda s, cr, uid, c: s._get_default_department_id(cr, uid, c),
        'company_id':
        lambda s, cr, uid, c: s._get_default_company_id(
            cr, uid, s._get_default_department_id(cr, uid, c), c),
        'color':
        0,
        'date_last_stage_update':
        fields.datetime.now,
    }

    _group_by_full = {'stage_id': _read_group_stage_ids}

    def onchange_job(self, cr, uid, ids, job_id=False, context=None):
        department_id = False
        if job_id:
            job_record = self.pool.get('hr.job').browse(cr,
                                                        uid,
                                                        job_id,
                                                        context=context)
            department_id = job_record and job_record.department_id and job_record.department_id.id or False
            user_id = job_record and job_record.user_id and job_record.user_id.id or False
        return {'value': {'department_id': department_id, 'user_id': user_id}}

    def onchange_department_id(self,
                               cr,
                               uid,
                               ids,
                               department_id=False,
                               stage_id=False,
                               context=None):
        if not stage_id:
            stage_id = self.stage_find(cr,
                                       uid, [],
                                       department_id, [('fold', '=', False)],
                                       context=context)
        return {'value': {'stage_id': stage_id}}

    def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
        data = {
            'partner_phone': False,
            'partner_mobile': False,
            'email_from': False
        }
        if partner_id:
            addr = self.pool.get('res.partner').browse(cr, uid, partner_id,
                                                       context)
            data.update({
                'partner_phone': addr.phone,
                'partner_mobile': addr.mobile,
                'email_from': addr.email
            })
        return {'value': data}

    def stage_find(self,
                   cr,
                   uid,
                   cases,
                   section_id,
                   domain=[],
                   order='sequence',
                   context=None):
        """ Override of the base.stage method
            Parameter of the stage search taken from the lead:
            - department_id: if set, stages must belong to this section or
              be a default case
        """
        if isinstance(cases, (int, long)):
            cases = self.browse(cr, uid, cases, context=context)
        # collect all section_ids
        department_ids = []
        if section_id:
            department_ids.append(section_id)
        for case in cases:
            if case.department_id:
                department_ids.append(case.department_id.id)
        # OR all section_ids and OR with case_default
        search_domain = []
        if department_ids:
            search_domain += ['|', ('department_id', 'in', department_ids)]
        search_domain.append(('department_id', '=', False))
        # AND with the domain in parameter
        search_domain += list(domain)
        # perform search, return the first found
        stage_ids = self.pool.get('hr.recruitment.stage').search(
            cr, uid, search_domain, order=order, context=context)
        if stage_ids:
            return stage_ids[0]
        return False

    def action_makeMeeting(self, cr, uid, ids, context=None):
        """ This opens Meeting's calendar view to schedule meeting on current applicant
            @return: Dictionary value for created Meeting view
        """
        applicant = self.browse(cr, uid, ids[0], context)
        applicant_ids = []
        if applicant.partner_id:
            applicant_ids.append(applicant.partner_id.id)
        if applicant.department_id and applicant.department_id.manager_id and applicant.department_id.manager_id.user_id and applicant.department_id.manager_id.user_id.partner_id:
            applicant_ids.append(
                applicant.department_id.manager_id.user_id.partner_id.id)
        category = self.pool.get('ir.model.data').get_object(
            cr, uid, 'hr_recruitment', 'categ_meet_interview', context)
        res = self.pool.get('ir.actions.act_window').for_xml_id(
            cr, uid, 'calendar', 'action_calendar_event', context)
        res['context'] = {
            'default_partner_ids': applicant_ids,
            'default_user_id': uid,
            'default_name': applicant.name,
            'default_categ_ids': category and [category.id] or False,
        }
        return res

    def action_start_survey(self, cr, uid, ids, context=None):
        context = context if context else {}
        applicant = self.browse(cr, uid, ids, context=context)[0]
        survey_obj = self.pool.get('survey.survey')
        response_obj = self.pool.get('survey.user_input')
        # create a response and link it to this applicant
        if not applicant.response_id:
            response_id = response_obj.create(
                cr,
                uid, {
                    'survey_id': applicant.survey.id,
                    'partner_id': applicant.partner_id.id
                },
                context=context)
            self.write(cr,
                       uid,
                       ids[0], {'response_id': response_id},
                       context=context)
        else:
            response_id = applicant.response_id.id
        # grab the token of the response and start surveying
        response = response_obj.browse(cr, uid, response_id, context=context)
        context.update({'survey_token': response.token})
        return survey_obj.action_start_survey(cr,
                                              uid, [applicant.survey.id],
                                              context=context)

    def action_print_survey(self, cr, uid, ids, context=None):
        """ If response is available then print this response otherwise print survey form (print template of the survey) """
        context = context if context else {}
        applicant = self.browse(cr, uid, ids, context=context)[0]
        survey_obj = self.pool.get('survey.survey')
        response_obj = self.pool.get('survey.user_input')
        if not applicant.response_id:
            return survey_obj.action_print_survey(cr,
                                                  uid, [applicant.survey.id],
                                                  context=context)
        else:
            response = response_obj.browse(cr,
                                           uid,
                                           applicant.response_id.id,
                                           context=context)
            context.update({'survey_token': response.token})
            return survey_obj.action_print_survey(cr,
                                                  uid, [applicant.survey.id],
                                                  context=context)

    def action_get_attachment_tree_view(self, cr, uid, ids, context=None):
        model, action_id = self.pool.get('ir.model.data').get_object_reference(
            cr, uid, 'base', 'action_attachment')
        action = self.pool.get(model).read(cr, uid, action_id, context=context)
        action['context'] = {
            'default_res_model': self._name,
            'default_res_id': ids[0]
        }
        action['domain'] = str(
            ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)])
        return action

    def message_get_suggested_recipients(self, cr, uid, ids, context=None):
        recipients = super(hr_applicant,
                           self).message_get_suggested_recipients(
                               cr, uid, ids, context=context)
        for applicant in self.browse(cr, uid, ids, context=context):
            if applicant.partner_id:
                self._message_add_suggested_recipient(
                    cr,
                    uid,
                    recipients,
                    applicant,
                    partner=applicant.partner_id,
                    reason=_('Contact'))
            elif applicant.email_from:
                self._message_add_suggested_recipient(
                    cr,
                    uid,
                    recipients,
                    applicant,
                    email=applicant.email_from,
                    reason=_('Contact Email'))
        return recipients

    def message_new(self, cr, uid, msg, custom_values=None, context=None):
        """ Overrides mail_thread message_new that is called by the mailgateway
            through message_process.
            This override updates the document according to the email.
        """
        if custom_values is None:
            custom_values = {}
        val = msg.get('from').split('<')[0]
        defaults = {
            'name': msg.get('subject') or _("No Subject"),
            'partner_name': val,
            'email_from': msg.get('from'),
            'email_cc': msg.get('cc'),
            'user_id': False,
            'partner_id': msg.get('author_id', False),
        }
        if msg.get('priority'):
            defaults['priority'] = msg.get('priority')
        defaults.update(custom_values)
        return super(hr_applicant, self).message_new(cr,
                                                     uid,
                                                     msg,
                                                     custom_values=defaults,
                                                     context=context)

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {}
        context['mail_create_nolog'] = True
        if vals.get(
                'department_id') and not context.get('default_department_id'):
            context['default_department_id'] = vals.get('department_id')
        if vals.get('job_id') or context.get('default_job_id'):
            job_id = vals.get('job_id') or context.get('default_job_id')
            vals.update(
                self.onchange_job(cr, uid, [], job_id,
                                  context=context)['value'])
        obj_id = super(hr_applicant, self).create(cr,
                                                  uid,
                                                  vals,
                                                  context=context)
        applicant = self.browse(cr, uid, obj_id, context=context)
        if applicant.job_id:
            name = applicant.partner_name if applicant.partner_name else applicant.name
            self.pool['hr.job'].message_post(
                cr,
                uid, [applicant.job_id.id],
                body=_('New application from %s') % name,
                subtype="hr_recruitment.mt_job_applicant_new",
                context=context)
        return obj_id

    def write(self, cr, uid, ids, vals, context=None):
        if isinstance(ids, (int, long)):
            ids = [ids]
        res = True

        # user_id change: update date_open
        if vals.get('user_id'):
            vals['date_open'] = fields.datetime.now()
        # stage_id: track last stage before update
        if 'stage_id' in vals:
            vals['date_last_stage_update'] = fields.datetime.now()
            for applicant in self.browse(cr, uid, ids, context=None):
                vals['last_stage_id'] = applicant.stage_id.id
                res = super(hr_applicant, self).write(cr,
                                                      uid, [applicant.id],
                                                      vals,
                                                      context=context)
        else:
            res = super(hr_applicant, self).write(cr,
                                                  uid,
                                                  ids,
                                                  vals,
                                                  context=context)

        # post processing: if job changed, post a message on the job
        if vals.get('job_id'):
            for applicant in self.browse(cr, uid, ids, context=None):
                name = applicant.partner_name if applicant.partner_name else applicant.name
                self.pool['hr.job'].message_post(
                    cr,
                    uid, [vals['job_id']],
                    body=_('New application from %s') % name,
                    subtype="hr_recruitment.mt_job_applicant_new",
                    context=context)

        # post processing: if stage changed, post a message in the chatter
        if vals.get('stage_id'):
            stage = self.pool['hr.recruitment.stage'].browse(cr,
                                                             uid,
                                                             vals['stage_id'],
                                                             context=context)
            if stage.template_id:
                # TDENOTE: probably factorize me in a message_post_with_template generic method FIXME
                compose_ctx = dict(context, active_ids=ids)
                compose_id = self.pool['mail.compose.message'].create(
                    cr,
                    uid, {
                        'model': self._name,
                        'composition_mode': 'mass_mail',
                        'template_id': stage.template_id.id,
                        'same_thread': True,
                        'post': True,
                        'notify': True,
                    },
                    context=compose_ctx)
                self.pool['mail.compose.message'].write(
                    cr,
                    uid, [compose_id],
                    self.pool['mail.compose.message'].onchange_template_id(
                        cr,
                        uid, [compose_id],
                        stage.template_id.id,
                        'mass_mail',
                        self._name,
                        False,
                        context=compose_ctx)['value'],
                    context=compose_ctx)
                self.pool['mail.compose.message'].send_mail(
                    cr, uid, [compose_id], context=compose_ctx)
        return res

    def create_employee_from_applicant(self, cr, uid, ids, context=None):
        """ Create an hr.employee from the hr.applicants """
        if context is None:
            context = {}
        hr_employee = self.pool.get('hr.employee')
        model_data = self.pool.get('ir.model.data')
        act_window = self.pool.get('ir.actions.act_window')
        emp_id = False
        for applicant in self.browse(cr, uid, ids, context=context):
            address_id = contact_name = False
            if applicant.partner_id:
                address_id = self.pool.get('res.partner').address_get(
                    cr, uid, [applicant.partner_id.id], ['contact'])['contact']
                contact_name = self.pool.get('res.partner').name_get(
                    cr, uid, [applicant.partner_id.id])[0][1]
            if applicant.job_id and (applicant.partner_name or contact_name):
                applicant.job_id.write(
                    {
                        'no_of_hired_employee':
                        applicant.job_id.no_of_hired_employee + 1
                    },
                    context=context)
                create_ctx = dict(context, mail_broadcast=True)
                emp_id = hr_employee.create(
                    cr,
                    uid, {
                        'name':
                        applicant.partner_name or contact_name,
                        'job_id':
                        applicant.job_id.id,
                        'address_home_id':
                        address_id,
                        'department_id':
                        applicant.department_id.id or False,
                        'address_id':
                        applicant.company_id
                        and applicant.company_id.partner_id
                        and applicant.company_id.partner_id.id or False,
                        'work_email':
                        applicant.department_id
                        and applicant.department_id.company_id
                        and applicant.department_id.company_id.email or False,
                        'work_phone':
                        applicant.department_id
                        and applicant.department_id.company_id
                        and applicant.department_id.company_id.phone or False,
                    },
                    context=create_ctx)
                self.write(cr,
                           uid, [applicant.id], {'emp_id': emp_id},
                           context=context)
                self.pool['hr.job'].message_post(
                    cr,
                    uid, [applicant.job_id.id],
                    body=_('New Employee %s Hired') % applicant.partner_name
                    if applicant.partner_name else applicant.name,
                    subtype="hr_recruitment.mt_job_applicant_hired",
                    context=context)
            else:
                raise osv.except_osv(
                    _('Warning!'),
                    _('You must define an Applied Job and a Contact Name for this applicant.'
                      ))

        action_model, action_id = model_data.get_object_reference(
            cr, uid, 'hr', 'open_view_employee_list')
        dict_act_window = act_window.read(cr, uid, [action_id], [])[0]
        if emp_id:
            dict_act_window['res_id'] = emp_id
        dict_act_window['view_mode'] = 'form,tree'
        return dict_act_window

    def get_empty_list_help(self, cr, uid, help, context=None):
        context['empty_list_help_model'] = 'hr.job'
        context['empty_list_help_id'] = context.get('default_job_id', None)
        context['empty_list_help_document_name'] = _("job applicants")
        return super(hr_applicant, self).get_empty_list_help(cr,
                                                             uid,
                                                             help,
                                                             context=context)
Example #45
0
                cr, uid, line.taxes_id, line.price, line.qty, line.product_id, line.back_order_id.partner_id
            )
            cur = line.back_order_id.pricelist_id.currency_id
            res[line.id] = cur_obj.round(cr, uid, cur, taxes["total"])
        return res

    def _get_uom_id(self, cr, uid, context=None):
        try:
            proxy = self.pool.get("ir.model.data")
            result = proxy.get_object_reference(cr, uid, "product", "product_uom_unit")
            return result[1]
        except Exception, ex:
            return False

    _columns = {
        #        'location_destination_id': fields.many2one('stock.location', 'Stock Destination Location'),
        #        'location_id': fields.many2one('stock.location', 'Stock Source Location'),
        "product_id": fields.many2one("product.product", "Product"),
        "back_order_id": fields.many2one("back.to.back.order", "Back Order"),
        "qty": fields.float("Quantity"),
        "price": fields.float("Unit Price"),
        "subtotal": fields.function(_amount_line, string="Subtotal", digits_compute=dp.get_precision("Account")),
        "taxes_id": fields.many2many("account.tax", "purchase_order_taxe", "ord_id", "tax_id", "Taxes"),
        "product_uom": fields.many2one("product.uom", "Product Unit of Measure", required=True),
    }

    _defaults = {"product_uom": _get_uom_id}


# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
Example #46
0
class hr_job(osv.osv):
    _inherit = "hr.job"
    _name = "hr.job"
    _inherits = {'mail.alias': 'alias_id'}

    def _get_attached_docs(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        attachment_obj = self.pool.get('ir.attachment')
        for job_id in ids:
            applicant_ids = self.pool.get('hr.applicant').search(
                cr, uid, [('job_id', '=', job_id)], context=context)
            res[job_id] = attachment_obj.search(
                cr,
                uid, [
                    '|', '&', ('res_model', '=', 'hr.job'),
                    ('res_id', '=', job_id), '&',
                    ('res_model', '=', 'hr.applicant'),
                    ('res_id', 'in', applicant_ids)
                ],
                context=context)
        return res

    def _count_all(self, cr, uid, ids, field_name, arg, context=None):
        Applicant = self.pool['hr.applicant']
        return {
            job_id: {
                'application_count':
                Applicant.search_count(cr,
                                       uid, [('job_id', '=', job_id)],
                                       context=context),
                'documents_count':
                len(
                    self._get_attached_docs(cr,
                                            uid, [job_id],
                                            field_name,
                                            arg,
                                            context=context)[job_id])
            }
            for job_id in ids
        }

    _columns = {
        'survey_id':
        fields.many2one(
            'survey.survey',
            'Interview Form',
            help=
            "Choose an interview form for this job position and you will be able to print/answer this interview from all applicants who apply for this job"
        ),
        'alias_id':
        fields.many2one(
            'mail.alias',
            'Alias',
            ondelete="restrict",
            required=True,
            help=
            "Email alias for this job position. New emails will automatically "
            "create new applicants for this job position."),
        'address_id':
        fields.many2one('res.partner',
                        'Job Location',
                        help="Address where employees are working"),
        'application_ids':
        fields.one2many('hr.applicant', 'job_id', 'Applications'),
        'application_count':
        fields.function(_count_all,
                        type='integer',
                        string='Applications',
                        multi=True),
        'manager_id':
        fields.related('department_id',
                       'manager_id',
                       type='many2one',
                       string='Department Manager',
                       relation='hr.employee',
                       readonly=True,
                       store=True),
        'document_ids':
        fields.function(_get_attached_docs,
                        type='one2many',
                        relation='ir.attachment',
                        string='Applications'),
        'documents_count':
        fields.function(_count_all,
                        type='integer',
                        string='Documents',
                        multi=True),
        'user_id':
        fields.many2one('res.users',
                        'Recruitment Responsible',
                        track_visibility='onchange'),
        'color':
        fields.integer('Color Index'),
    }

    def _address_get(self, cr, uid, context=None):
        user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
        return user.company_id.partner_id.id

    _defaults = {'address_id': _address_get}

    def _auto_init(self, cr, context=None):
        """Installation hook to create aliases for all jobs and avoid constraint errors."""
        return self.pool.get('mail.alias').migrate_to_alias(
            cr,
            self._name,
            self._table,
            super(hr_job, self)._auto_init,
            'hr.applicant',
            self._columns['alias_id'],
            'name',
            alias_prefix='job+',
            alias_defaults={'job_id': 'id'},
            context=context)

    def create(self, cr, uid, vals, context=None):
        alias_context = dict(context,
                             alias_model_name='hr.applicant',
                             alias_parent_model_name=self._name)
        job_id = super(hr_job, self).create(cr,
                                            uid,
                                            vals,
                                            context=alias_context)
        job = self.browse(cr, uid, job_id, context=context)
        self.pool.get('mail.alias').write(cr, uid, [job.alias_id.id], {
            'alias_parent_thread_id': job_id,
            "alias_defaults": {
                'job_id': job_id
            }
        }, context)
        return job_id

    def unlink(self, cr, uid, ids, context=None):
        # Cascade-delete mail aliases as well, as they should not exist without the job position.
        mail_alias = self.pool.get('mail.alias')
        alias_ids = [
            job.alias_id.id
            for job in self.browse(cr, uid, ids, context=context)
            if job.alias_id
        ]
        res = super(hr_job, self).unlink(cr, uid, ids, context=context)
        mail_alias.unlink(cr, uid, alias_ids, context=context)
        return res

    def action_print_survey(self, cr, uid, ids, context=None):
        job = self.browse(cr, uid, ids, context=context)[0]
        survey_id = job.survey_id.id
        return self.pool.get('survey.survey').action_print_survey(
            cr, uid, [survey_id], context=context)

    def action_get_attachment_tree_view(self, cr, uid, ids, context=None):
        #open attachments of job and related applicantions.
        model, action_id = self.pool.get('ir.model.data').get_object_reference(
            cr, uid, 'base', 'action_attachment')
        action = self.pool.get(model).read(cr, uid, action_id, context=context)
        applicant_ids = self.pool.get('hr.applicant').search(
            cr, uid, [('job_id', 'in', ids)], context=context)
        action['context'] = {
            'default_res_model': self._name,
            'default_res_id': ids[0]
        }
        action['domain'] = str([
            '|', '&', ('res_model', '=', 'hr.job'), ('res_id', 'in', ids), '&',
            ('res_model', '=', 'hr.applicant'), ('res_id', 'in', applicant_ids)
        ])
        return action

    def action_set_no_of_recruitment(self, cr, uid, id, value, context=None):
        return self.write(cr,
                          uid, [id], {'no_of_recruitment': value},
                          context=context)
Example #47
0
class stock_fill_inventory(osv.osv_memory):
    _name = "stock.fill.inventory"
    _description = "Import Inventory"

    def _default_location(self, cr, uid, ids, context=None):
        try:
            location = self.pool.get("ir.model.data").get_object(cr, uid, "stock", "stock_location_stock")
            location.check_access_rule("read", context=context)
            location_id = location.id
        except (ValueError, orm.except_orm), e:
            return False
        return location_id or False

    _columns = {
        "location_id": fields.many2one("stock.location", "Location", required=True),
        "recursive": fields.boolean(
            "Include children",
            help="If checked, products contained in child locations of selected location will be included as well.",
        ),
        "set_stock_zero": fields.boolean(
            "Set to zero",
            help="If checked, all product quantities will be set to zero to help ensure a real physical inventory is done",
        ),
    }
    _defaults = {"location_id": _default_location}

    def view_init(self, cr, uid, fields_list, context=None):
        """
         Creates view dynamically and adding fields at runtime.
         @param self: The object pointer.
class ids_hr_employee_separation(osv.osv): 
    
    def separation_submit(self, cr, uid, ids, context=None):
        """Initiate workflow- submit the form. """
        self._check_resignations(cr, uid, ids, context=context)
        users= self.pool.get('res.users')
    	#code to update employee working status
    	self._update_employee_working_status(cr, uid, ids, 'on_resign', context=None)

        resign=self.browse(cr, uid, ids, context=None)
        if users.has_group(cr, uid, 'ids_emp.group_location_hr'):
            print "------------------------------location--outer------------------------"
            if resign.employee_id.parent_id.parent_id.id==7626:
                print "------------------------------res--------------------------"
                url="http://ids-erp.idsil.loc:8069/web"
                values = {
                'subject': 'Resignation' + '-' + resign.employee_id.name,
                'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Intiated.Please take necessary action.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/>Url:'+url,
                'email_to': resign.employee_id.parent_id.work_email,
                'email_from': '*****@*****.**',
                  }  
            else:
                print "------------------------------location--------------------------"
                url="http://ids-erp.idsil.loc:8069/web"
                values = {
                'subject': 'Resignation' + '-' + resign.employee_id.name,
                'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Intiated.Please take necessary action.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/>Url:'+url,
                'email_to': resign.employee_id.division.hod_email,
                'email_cc': resign.employee_id.parent_id.work_email,
                'email_from': '*****@*****.**',
                  }

        #---------------------------------------------------------------
            mail_obj = self.pool.get('mail.mail') 
            msg_id = mail_obj.create(cr, uid, values, context=context) 
            if msg_id: 
                mail_obj.send(cr, uid, [msg_id], context=context)
        
        elif users.has_group(cr, uid, 'ids_emp.group_business_head'):
            print "------------------------------business--------------------------"
            url="http://ids-erp.idsil.loc:8069/web"
            values = {
            'subject': 'Resignation' + '-' + resign.employee_id.name,
            'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Intiated.Please take necessary action.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/>Url:'+url,
            'email_to': resign.employee_id.division.hr_email,
            'email_from': '*****@*****.**',
              }
        #---------------------------------------------------------------
            mail_obj = self.pool.get('mail.mail') 
            msg_id = mail_obj.create(cr, uid, values, context=context) 
            if msg_id: 
                mail_obj.send(cr, uid, [msg_id], context=context)
        else:
            print "------------------------------manager--------------------------"
            url="http://ids-erp.idsil.loc:8069/web"
            values = {
            'subject': 'Resignation' + '-' + resign.employee_id.name,
            'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Intiated.Please take necessary action.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/>Url:'+url,
            'email_to': resign.employee_id.division.hod_email,
            'email_cc': resign.employee_id.division.hr_email,
            'email_from': '*****@*****.**',
              }
        #---------------------------------------------------------------
            mail_obj = self.pool.get('mail.mail') 
            msg_id = mail_obj.create(cr, uid, values, context=context) 
            if msg_id: 
                mail_obj.send(cr, uid, [msg_id], context=context)
        	
    	return self.write(cr, uid, ids, {'state': 'confirm'})   	 
      
    def separation_first_validate(self, cr, uid, ids, context=None):	
        """Validating the form by Manager and update the working status. """
        self._check_validate(cr, uid, ids, context=context)
    	#code to update employee working status
    	self._update_employee_working_status(cr, uid, ids, 'resigned', context=None)	
        
        resign=self.browse(cr, uid, ids, context=None)
        url="http://ids-erp.idsil.loc:8069/web"
        values = {
        'subject': 'Resignation' + '-' + resign.employee_id.name,
        'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Approved.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/><br/>Url:'+url,
        'email_to': resign.employee_id.parent_id.work_email,
        'email_cc': resign.employee_id.division.hr_email,
        'email_from': '*****@*****.**',
          }
        #---------------------------------------------------------------
        mail_obj = self.pool.get('mail.mail') 
        msg_id = mail_obj.create(cr, uid, values, context=context) 
        if msg_id: 
            mail_obj.send(cr, uid, [msg_id], context=context)
        

        return self.write(cr, uid, ids, {'state':'approve'})      
    
    def separation_second_validate(self, cr, uid, ids, context=None):   
        """Final validation by HOD. """ 
        now=datetime.now()
        current = now.strftime('%Y-%m-%d')   
        self._check_validate(cr, uid, ids, context=context)

    	#code to update employee working status
    	self._update_employee_working_status(cr, uid, ids, 'resigned', context=None)
        
        resign=self.browse(cr, uid, ids, context=None)
        if resign.last_date>current:
            raise osv.except_osv(_('Warning!'), _('You can not validate before last date in company!'))
        if resign.employee_id.parent_id.parent_id.id==7626:
            print "------------------------------res--------------------------"
            url="http://ids-erp.idsil.loc:8069/web"
            values = {
            'subject': 'Resignation' + '-' + resign.employee_id.name,
            'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Intiated.Please take necessary action.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/>Url:'+url,
            'email_to': resign.employee_id.parent_id.work_email,
            'email_from': '*****@*****.**',
              }  
        else:
            url="http://ids-erp.idsil.loc:8069/web"
            values = {
            'subject': 'Resignation' + '-' + resign.employee_id.name,
            'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Validated.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.\<br/><br/>Url:'+url,
            'email_to': resign.employee_id.parent_id.work_email,
            'email_cc': resign.employee_id.division.hod_email,
            'email_from': '*****@*****.**',
              }
        #---------------------------------------------------------------
        mail_obj = self.pool.get('mail.mail') 
        msg_id = mail_obj.create(cr, uid, values, context=context) 
        if msg_id: 
            mail_obj.send(cr, uid, [msg_id], context=context)
            
        ee = self.pool.get('hr.employee').browse(cr, uid, resign.employee_id, context=context)
        emp_busi_id = self.pool.get('ids.business.information').search(cr, uid , [('employee_id','=',resign.employee_id.id)], context=context) 
        eb = self.pool.get('ids.business.information').browse(cr, uid, emp_busi_id[0], context=context)
        emp_tech_id = self.pool.get('ids.technical.information').search(cr, uid , [('employee_id','=',resign.employee_id.id)], context=context)
        et = self.pool.get('ids.technical.information').browse(cr, uid, emp_tech_id[0], context=context)
        res = {
               'employee_id':resign.employee_id.id,
               'job_id':resign.employee_id.job_id.id,
               'department_id':resign.employee_id.department_id.id,
               'dob':resign.employee_id.birthday,
               'division_id':resign.employee_id.division.id,
               'location_id':resign.employee_id.office_location.id,
               'gender':resign.employee_id.gender,
               'mobile_no':resign.employee_id.mobile_phone,
               'joining_date':resign.employee_id.joining_date,
               'confirmation_status':resign.employee_id.confirmation_status.title(),
               'resign_id':resign.id,
               'capture_date':resign.capture_date,
               'last_date':resign.last_date,
               'email_control':eb.email_control,
               'internet_control':eb.internet_control,
               'remote_control':eb.remote_control,
               'software_requirement':eb.software_requirements,
               'application_share':eb.application_share_access,
               'data_backup':eb.backup_remarks,
               'allocation_it_asset':et.allocation_of_itassets or False,
               'email_id_tech':et.email_created or False,
               'internet_control_tech':et.internet_access_control or False,
               'backup_setup_tech':et.backup_setup or False,
               'software_requirement_tech': et.software_provisioning_and_access_control or False,
               'application_share_tech':et.application_share_access or False,
               'state':'phase1',
               
               } 
        self.pool.get('emp.no.dues').create(cr, uid, res)
        return self.write(cr, uid, ids, {'state':'done'})
    
    def separation_refuse(self, cr, uid, ids, context=None):
        """In case, resignation of employee is refused. """
        
        #code to update employee working status
        self._update_employee_working_status(cr, uid, ids, 'working', context=None)
        
        resign=self.browse(cr, uid, ids, context=None)
        url="http://ids-erp.idsil.loc:8069/web"
        values = {
        'subject': 'Resignation' + '-' + resign.employee_id.name,
        'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Refused.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/>Url:'+url,
        'email_to': resign.employee_id.parent_id.work_email,
        'email_cc':  resign.employee_id.division.hr_email,
        'email_from': '*****@*****.**',
          }
        #---------------------------------------------------------------
        mail_obj = self.pool.get('mail.mail') 
        msg_id = mail_obj.create(cr, uid, values, context=context) 
        if msg_id: 
            mail_obj.send(cr, uid, [msg_id], context=context)
        
        
        return self.write(cr, uid, ids, {'state': 'cancel'})
    
    def refuse_location(self, cr, uid, ids, context=None):
        """In case, resignation of employee is refused. """
        
        #code to update employee working status
        self._update_employee_working_status(cr, uid, ids, 'working', context=None)
        
        resign=self.browse(cr, uid, ids, context=None)
        url="http://ids-erp.idsil.loc:8069/web"
        values = {
        'subject': 'Resignation' + '-' + resign.employee_id.name,
        'body_html': 'Resignation of' +' '+resign.employee_id.name+' '+'is Refused.<br/><br/><br/>Kindly do not reply.<br/>---This is auto generated email---<br/>Regards:<br/>ERP HR Team<br/>IDS Infotech LTD.<br/>Url:'+url,
        'email_to': resign.employee_id.parent_id.work_email,
        'email_from': '*****@*****.**',
          }
        #---------------------------------------------------------------
        mail_obj = self.pool.get('mail.mail') 
        msg_id = mail_obj.create(cr, uid, values, context=context) 
        if msg_id: 
            mail_obj.send(cr, uid, [msg_id], context=context)
        
        
        return self.write(cr, uid, ids, {'state': 'cancel'})
    
    def _update_employee_working_status(self, cr, uid, ids, working_status, context=None):
        """Updating final working status. """
        obj_separation = self.browse(cr, uid, ids)
        sep_emp_id = 0	
        obj_emp = self.pool.get('hr.employee')    
        for record in obj_separation:
            sep_emp_id = record.employee_id.id
        
        obj_emp.write(cr, SUPERUSER_ID , [sep_emp_id], {'working_status':working_status})
        
    def _initiated_get(self, cr, uid, context=None):        
        emp_id = context.get('default_employee_id', False)
        if emp_id:
            return emp_id
        ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)], context=context)
        if ids:
            return ids[0]
        return False    	
	
    
    _name = 'ids.hr.employee.separation'        
    _inherit = ['mail.thread', 'ir.needaction_mixin'] 
    _description = "Employee Separation"
    _columns = {
                'rgn_number':fields.char('RGN Number', size=15, readonly=True),
                'initiated_by': fields.many2one('hr.employee', 'Resign Initiated By', required=True),
                'employee_id': fields.many2one('hr.employee', 'Employee', required=True),
                'emp_code': fields.char('Employee Code', size=20),
                'department_id':fields.many2one('hr.department', 'Department'),
                'job_id': fields.many2one('hr.job', 'Designation'),
                'confirmation_status': fields.related('employee_id', 'confirmation_status', type='char', relation='hr.employee', string='Confirmation Status', store=True, readonly=True),
                'separation_type': fields.many2one('ids.hr.employee.separation.type', 'Resignation Type', required=True),
                'rgn_accepted':fields.selection([('yes', 'Yes'),
                                           ('no', 'No'),
                                           ('na', 'N/A')], 'Resignation Accepted', required=True),
                'reason': fields.many2one('ids.hr.employee.separation.reason', 'Reason', required=True),
                'eligible_rehire': fields.boolean('Eligible for rehire?'),
                'capture_date': fields.date('Capture date', required=True),
                'last_date': fields.date('Last date in company', required=True),
#                 'interview_by': fields.many2one('hr.employee', 'Interview By', required=True),
                'user_id':fields.related('employee_id', 'user_id', type='many2one', relation='res.users', string='User', store=True),
                'manager_id1': fields.many2one('hr.employee', 'First Approval', invisible=False, readonly=True, help='This area is automatically filled by the user who approve/validate the resignation at first level'),
                'manager_id2': fields.many2one('hr.employee', 'Second Approval', invisible=False, readonly=True, help='This area is automatically filled by the user who approve/validate the resignation at second level'),
                'notes': fields.text('Notes'),                
                'state': fields.selection([('draft', 'Draft'),
                                           ('confirm', 'Waiting for Approval'),
                                           ('approve', 'Approved'),
                                           ('done', 'Validated'),
                                           ('cancel', 'Refused')], 'Status', readonly=True),
                'full_final_status': fields.selection([('pending', 'Pending'), ('done', 'Done')],'Full & Final Status'),                                                   
    }
    _rec_name = 'rgn_number'
    _defaults = {
        'state': 'draft', 
        'capture_date':fields.date.context_today,
        'full_final_status':'pending',
        #'initiated_by': _initiated_get
    }
    
    def create(self, cr, uid, vals, context=None):
        """Create the unique id used for F&F """
        vals['rgn_number']=self.pool.get('ir.sequence').get(cr, uid,'ids.hr.employee.separation')
        res=super(ids_hr_employee_separation, self).create(cr, uid, vals)
        return res
    
    def write(self, cr, uid, ids, vals, context=None):        
        """Updating final working status. """        
        if vals.get('full_final_status', False):
            if (vals['full_final_status'] == 'done'):                               
                self._update_employee_working_status(cr, uid, ids, 'exit', context=None)                                     
            if (vals['full_final_status'] == 'pending'):
                self._update_employee_working_status(cr, uid, ids, 'resigned', context=None)
        res=super(ids_hr_employee_separation, self).write(cr, uid, ids, vals)
        return res
    
    def unlink(self, cr, uid, ids, context=None):
        
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.state not in ['draft']:
                raise osv.except_osv(_('Warning!'),_('You cannot delete a resignation which is not in draft state.'))
        return super(ids_hr_employee_separation, self).unlink(cr, uid, ids, context)    
    
    def onchange_employee_id(self, cr, uid, ids, employee_id, capture_date, context=None):
        """get associated values of employee onchange of employee id. """
        value = {'department_id': False}
        notice_period_days=0
        if employee_id:
            employee = self.pool.get('hr.employee').browse(cr, uid, employee_id)
            notice_period_days = int(employee.notice)
            last_date = datetime.strptime(capture_date, "%Y-%m-%d")+timedelta(days=notice_period_days)
            value['department_id'] = employee.department_id.id
            value['emp_code'] = employee.emp_code
            value['job_id'] = employee.job_id.id
            value['initiated_by'] = employee.parent_id.id
            value['initiated_by'] = employee.parent_id.id
            value['last_date'] = last_date
            if employee.employment_type_id=='regular':
                value['confirmation_status'] = employee.confirmation_status
            else:
                value['confirmation_status'] = 'NA'
        return {'value': value}
    
    def _check_resignations(self, cr, uid, ids, context=None):        
        """Constraints on submitting resignation. """
        for obj in self.browse(cr, uid, ids, context=context):
            res_user_id = obj.user_id.id
            
        resignation_ids = self.search(cr, uid, [('id','not in',ids),('user_id', '=', res_user_id),('state', '!=', 'refuse')], context=context)
        
        if resignation_ids:
            raise osv.except_osv(_('Warning!'), _('Resignation is already in progress for this employee'))
        
        return True
    
    def _check_validate(self, cr, uid, ids, context=None):
        """Constraints on validating resignation. """
        users_obj = self.pool.get('res.users')
        
        if not users_obj.has_group(cr, uid, 'base.group_hr_manager'):
            for separation in self.browse(cr, uid, ids, context=context):
                if separation.employee_id.user_id.id == uid:
                    raise osv.except_osv(_('Warning!'), _('You cannot approve your own Resignation.'))
                if (separation.manager_id1 and separation.manager_id1.user_id.id == uid) or (separation.manager_id2 and separation.manager_id2.user_id.id == uid):
                    raise osv.except_osv(_('Warning!'), _('You have already approved the Resignation.'))
        return True
    
    def calculate_last_day(self, cr, uid, ids, employee_id, capture_date,context=None):       
        """Calculate last day from date of resignation. """
        notice_period_days=0
        if employee_id:
            employee = self.pool.get('hr.employee').browse(cr, uid,employee_id)     
            notice_period_days = int(employee.notice)
        last_date = datetime.strptime(capture_date, "%Y-%m-%d")+timedelta(days=notice_period_days)
        return {'value':{'last_date':datetime.strftime(last_date,DEFAULT_SERVER_DATE_FORMAT)}}
import os

class stock_import_inventory(osv.osv_memory):
    _name = "stock.import.inventory"
    _description = "Import Inventory"

    def _default_location(self, cr, uid, ids, context=None):
        try:
            loc_model, location_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock')
        except ValueError, e:
            return False
        return location_id or False

    _columns = {
        'location_id': fields.many2one('stock.location', 'Location', required=True),
        'import_file': fields.binary('File', filters="*.xls"),
        #to consider the product current inventory or not, if yes then add the current inventory to the upload excel quantity as the quantity to do physical inventory
        'consider_inventory': fields.boolean('Consider Current Inventory', select=True), 
        'all_done': fields.boolean('All Data Imported', readonly=True, select=True), 
        'result_line': fields.one2many('stock.import.inventory.result', 'import_id', 'Importing Result', readonly=True), 
        'file_template': fields.binary('Template File', readonly=True),
        'file_template_name': fields.char('Template File Name'),
    }
    
    def _get_template(self, cr, uid, context):
        cur_path = os.path.split(os.path.realpath(__file__))[0]
        path = os.path.join(cur_path,'stock_import_template.xls')
        data = open(path,'rb').read().encode('base64')
#        data = os.path.getsize(path)
        return data
Example #50
0
class reportes(osv.osv_memory):
    _name = "reportes"
    _description = "Exportar a excel"

    def exportar(self, cr, uid, ids, directory=".", context=None):
        #ExcelExportView.index()
        _cp_path = '/web/export/zb_excel_export'
        result = {}
        bal = []
        activo = 0
        pasivocapital = 0
        saldo = {}
        bal1 = []
        est = []
        balanza = []

        company = self.pool.get('res.company').browse(cr,
                                                      uid,
                                                      1,
                                                      context=context).name
        logo = self.pool.get('res.company').browse(cr, uid, 1,
                                                   context=context).logo
        acc_obj = self.pool.get('account.account')
        move_obj = self.pool.get('account.move.line')
        balanza_obj = self.pool.get('account.annual.balance')

        #_________________________________________Busqueda de las variables utilizadas para el reporte_______________________________________________#
        for reporte in self.browse(cr, uid, ids, context=context):
            id = reporte.id

#_________________________________________Declaracion de variables para realizar la consulta_________________________________________________#
        debit = 'debit' + reporte.mes
        credit = 'credit' + reporte.mes
        balance = 'balance' + reporte.mes

        #_________________________________________Consulta para sacar el reporte de Balance de comprobacion___________________________________________#
        if reporte.cero == True:
            if reporte.reporte == 'com':
                if reporte.mensual == True:  #  fiscalyear,
                    query = (
                        "select account_code, account_name, account_level, initial_balance, %s, %s, %s from account_annual_balance where fiscalyear = cast(%s as text) and account_level <= %s"
                        % (debit, credit, balance, reporte.periodo.name,
                           (int(reporte.nivel))))
                    cr.execute(
                        "select account_code, account_name, account_level, initial_balance, %s, %s, %s from account_annual_balance where fiscalyear = cast(%s as text) and account_level <= %s"
                        % (debit, credit, balance, reporte.periodo.name,
                           (int(reporte.nivel))))
                    resultado = cr.fetchall()
                    registros = cr.rowcount
                    cabeceras = {
                        0: 'Codigo',
                        1: 'Cuenta',
                        2: 'Nivel',
                        3: 'Saldo inicial',
                        4: 'Cargo',
                        5: 'Abono',
                        6: 'Saldo Final'
                    }  #cr.description
                elif reporte.mensual == False:
                    query = (
                        "select account_code, account_name, account_level, initial_balance, debit1, credit1, balance1, debit2, credit2, balance2, debit3, credit3, balance3, debit4, credit4, balance4, debit5, credit5, balance5, debit6, credit6, balance6, debit7, credit7, balance7, debit8, credit8, balance8, debit9, credit9, balance9, debit10, credit10, balance10, debit11, credit11, balance11, debit12, credit12, balance12 from account_annual_balance where fiscalyear = cast(%s as text) and account_level <= %s"
                        % (reporte.periodo.name, (int(reporte.nivel))))
                    cr.execute(
                        "select account_code, account_name, account_level, initial_balance, debit1, credit1, balance1, debit2, credit2, balance2, debit3, credit3, balance3, debit4, credit4, balance4, debit5, credit5, balance5, debit6, credit6, balance6, debit7, credit7, balance7, debit8, credit8, balance8, debit9, credit9, balance9, debit10, credit10, balance10, debit11, credit11, balance11, debit12, credit12, balance12 from account_annual_balance where fiscalyear = cast(%s as text) and account_level <= %s"
                        % (reporte.periodo.name, (int(reporte.nivel))))
                    resultado = cr.fetchall()
                    registros = cr.rowcount
                    cabeceras = cr.description
        elif reporte.cero == False:
            if reporte.reporte == 'com':
                if reporte.mensual == True:
                    query = (
                        "select account_code, account_name, account_level, initial_balance, %s, %s, %s from account_annual_balance where fiscalyear = cast(%s as text) and account_level <= %s and (%s) != 0"
                        % (debit, credit, balance, reporte.periodo.name,
                           (int(reporte.nivel)), balance))
                    cr.execute(
                        "select account_code, account_name, account_level, initial_balance, %s, %s, %s from account_annual_balance where fiscalyear = cast(%s as text) and account_level <= %s and (%s) != 0"
                        % (debit, credit, balance, reporte.periodo.name,
                           (int(reporte.nivel)), balance))
                    resultado = cr.fetchall()
                    registros = cr.rowcount
                    cabeceras = {
                        0: 'Codigo',
                        1: 'Cuenta',
                        2: 'Nivel',
                        3: 'Saldo inicial',
                        4: 'Cargo',
                        5: 'Abono',
                        6: 'Saldo Final'
                    }  #cr.description
                elif reporte.mensual == False:
                    query = (
                        "select account_code, account_name, account_level, initial_balance, debit1, credit1, balance1, debit2, credit2, balance2, debit3, credit3, balance3, debit4, credit4, balance4, debit5, credit5, balance5, debit6, credit6, balance6, debit7, credit7, balance7, debit8, credit8, balance8, debit9, credit9, balance9, debit10, credit10, balance10, debit11, credit11, balance11, debit12, credit12, balance12 from account_annual_balance where fiscalyear = cast(%s as text) and account_level <= %s and (balance1 + balance2 + balance3 + balance4 + balance5 + balance6 + balance7 + balance8 + balance9 + balance10 + balance11 + balance12) != 0"
                        % (reporte.periodo.name, (int(reporte.nivel))))
                    cr.execute(
                        "select account_code, account_name, account_level, initial_balance, debit1, credit1, balance1, debit2, credit2, balance2, debit3, credit3, balance3, debit4, credit4, balance4, debit5, credit5, balance5, debit6, credit6, balance6, debit7, credit7, balance7, debit8, credit8, balance8, debit9, credit9, balance9, debit10, credit10, balance10, debit11, credit11, balance11, debit12, credit12, balance12 from account_annual_balance where fiscalyear = cast(%s as text) and account_level <= %s and (balance1 + balance2 + balance3 + balance4 + balance5 + balance6 + balance7 + balance8 + balance9 + balance10 + balance11 + balance12) != 0"
                        % (reporte.periodo.name, (int(reporte.nivel))))
                    resultado = cr.fetchall()
                    registros = cr.rowcount
                    cabeceras = cr.description

#_________________________________________Consulta para sacar el reporte de Balance General_________________________________________________#

        if reporte.reporte == 'bal':

            acc_ids = acc_obj.search(cr, uid, [('type', '!=', 'view')])
            for cuenta in acc_obj.browse(cr, uid, acc_ids):
                balance = 0
                if reporte.movimiento == 1:
                    move_ids = move_obj.search(
                        cr, uid, [('period_id.fiscalyear_id.name', '=',
                                   reporte.periodo.name),
                                  ('account_id.id', '=', cuenta.id)])
                else:
                    move_ids = move_obj.search(
                        cr, uid, [('period_id.fiscalyear_id.name', '=',
                                   reporte.periodo.name),
                                  ('account_id.id', '=', cuenta.id),
                                  ('state', '!=', 'draft')])
                for move in move_obj.browse(cr, uid, move_ids):
                    balance += move.debit - move.credit
                if round(balance, 2) != 0.0:
                    if str(move.account_id.parent_id.code)[0:2] == '11':
                        if len(bal) == 0:
                            saldo = {0: '', 1: '', 2: ''}
                            bal.append(saldo)
                            saldo = {0: 'Activo Circulante', 1: '', 2: ''}
                            bal.append(saldo)
                        saldo = {0: move.account_id.name, 1: balance, 2: 'AC'}
                    elif str(move.account_id.parent_id.code)[0:2] == '12':
                        for af in bal:
                            a = af
                        if 'AF' not in str(a[2]):
                            saldo = {0: '', 1: '', 2: ''}
                            bal.append(saldo)
                            saldo = {0: 'Activo Fijo', 1: '', 2: ''}
                            bal.append(saldo)
                        saldo = {0: move.account_id.name, 1: balance, 2: 'AF'}
                #     bal.append(saldo)
                    elif str(move.account_id.parent_id.code)[0:2] == '13':
                        for ad in bal:
                            a = ad
                        if 'AD' not in str(a[2]):
                            saldo = {0: '', 1: '', 2: ''}
                            bal.append(saldo)
                            saldo = {0: 'Activo Fijo', 1: '', 2: ''}
                            bal.append(saldo)
                        saldo = {0: move.account_id.name, 1: balance, 2: 'AD'}
                #     bal.append(saldo)
                    elif str(move.account_id.parent_id.code)[0:2] == '21':
                        if len(bal1) == 0:
                            saldo = {0: '', 1: '', 2: ''}
                            bal1.append(saldo)
                            saldo = {0: 'Pasivo Corto Plazo', 1: '', 2: ''}
                            bal1.append(saldo)
                        saldo = {
                            0: move.account_id.name,
                            1: balance * -1,
                            2: 'PC'
                        }
                    elif str(move.account_id.parent_id.code)[0:2] == '22':
                        for ad in bal1:
                            a = ad
                        if 'PO' not in str(a[2]):
                            saldo = {0: '', 1: '', 2: ''}
                            bal1.append(saldo)
                            saldo = {
                                0: 'Pasivo Corto Plazo(Otros)',
                                1: '',
                                2: ''
                            }
                            bal1.append(saldo)
                        saldo = {
                            0: move.account_id.name,
                            1: balance * -1,
                            2: 'PO'
                        }
                    elif str(move.account_id.parent_id.code)[0:2] == '25':
                        for ad in bal1:
                            a = ad
                        if 'PL' not in str(a[2]):
                            saldo = {0: '', 1: '', 2: ''}
                            bal1.append(saldo)
                            saldo = {0: 'Pasivo Largo Plazo', 1: '', 2: ''}
                            bal1.append(saldo)
                        saldo = {
                            0: move.account_id.name,
                            1: balance * -1,
                            2: 'PL'
                        }
                    elif str(move.account_id.parent_id.code)[0:1] == '3':
                        for ad in bal1:
                            a = ad
                        if 'CT' not in str(a[2]):
                            saldo = {0: '', 1: '', 2: ''}
                            bal1.append(saldo)
                            saldo = {0: 'Capital', 1: '', 2: ''}
                            bal1.append(saldo)
                        saldo = {
                            0: move.account_id.name,
                            1: balance * -1,
                            2: 'CT'
                        }

                    if 'AC' in str(saldo[2]) or 'AF' in str(
                            saldo[2]) or 'AD' in str(saldo[2]):
                        activo += saldo[1]
                        bal.append(saldo)

                    elif 'PC' in str(saldo[2]) or 'PO' in str(
                            saldo[2]) or 'PL' in str(saldo[2]) or 'CT' in str(
                                saldo[2]):
                        pasivocapital += saldo[1]
                        bal1.append(saldo)
            saldo = {0: 'Suma Activo', 1: activo, 2: ''}
            bal.append(saldo)
            saldo = {0: 'Suma Pasivo + Capital', 1: pasivocapital, 2: ''}
            bal1.append(saldo)
#_________________________________________Consulta para sacar el reporte de Estado de resultados______________________________________________#
        elif reporte.reporte == 'est':
            ingresos = 0
            egresos = 0

            acc_ids = acc_obj.search(cr, uid, [('type', '!=', 'view')])
            for cuenta in acc_obj.browse(cr, uid, acc_ids):
                balance = 0
                acumuladoi = 0
                acumuladoe = 0

                if int(reporte.mes) < 10:
                    mes = '0' + str(reporte.mes) + '/' + reporte.periodo.name
                else:
                    mes = str(reporte.mes) + '/' + reporte.periodo.name

                period_obj = self.pool.get('account.period')
                #period_ids = period_obj.search(cr, uid, [('fiscalyear_id.name','=',reporte.periodo.name)])
                period_mes = period_obj.search(cr, uid, [('code', '=', mes)])
                for m in period_obj.browse(cr, uid, period_mes):
                    month = m.id

                #if reporte.mensual == True:
                #    move_ids = move_obj.search(cr, uid, [('period_id.fiscalyear_id.name','=',reporte.periodo.name),('account_id.id','=',cuenta.id),('period_id.code','=',mes)])
                #    move_acumulado = move_obj.search(cr, uid, [('period_id.fiscalyear_id.name','=',reporte.periodo.name),('account_id.id','=',cuenta.id),('period_id.id','<',month)])
                #else:
                move_ids = move_obj.search(cr, uid,
                                           [('period_id.fiscalyear_id.name',
                                             '=', reporte.periodo.name),
                                            ('account_id.id', '=', cuenta.id)])

                for move in move_obj.browse(cr, uid, move_ids):
                    if reporte.mensual == True:
                        if move.period_id.code == mes:
                            balance += move.debit - move.credit
                #for move_a in move_obj.browse(cr, uid, move_acumulado):
                    if str(move.account_id.parent_id.code)[0:1] == '5' or str(
                            move.account_id.parent_id.code)[0:2] == '92':
                        acumuladoi += move.debit - move.credit

                    if str(move.account_id.parent_id.code)[0:1] == '6' or str(
                            move.account_id.parent_id.code)[0:1] == '7' or str(
                                move.account_id.parent_id.code
                            )[0:1] == '8' or str(
                                move.account_id.parent_id.code)[0:2] == '91':
                        acumuladoe += move.debit - move.credit

                if round(balance, 2) != 0.0:
                    if str(move.account_id.parent_id.code)[0:1] == '5' or str(
                            move.account_id.parent_id.code)[0:2] == '92':
                        if len(est) == 0:
                            saldo = {
                                0: '',
                                1: '',
                                2: '',
                                #3: ''
                            }
                            est.append(saldo)
                            saldo = {
                                0: 'Ingresos',
                                1: '',
                                2: '',
                                #3: ''
                            }
                            est.append(saldo)
                        saldo = {
                            0: move.account_id.name,
                            1: balance,
                            #2: acumuladoi,
                            2: 'I'
                        }
                        ingresos += balance
                        est.append(saldo)
                    if str(move.account_id.parent_id.code)[0:1] == '6' or str(
                            move.account_id.parent_id.code)[0:1] == '7' or str(
                                move.account_id.parent_id.code
                            )[0:1] == '8' or str(
                                move.account_id.parent_id.code)[0:2] == '91':
                        for ad in est:
                            a = ad
                        if 'E' not in str(a[2]):
                            saldo = {
                                0: 'Suma Ingresos',
                                1: ingresos,
                                2: '',
                                #3: ''
                            }
                            est.append(saldo)
                            saldo = {
                                0: '',
                                1: '',
                                2: '',
                                #3: ''
                            }
                            est.append(saldo)
                            saldo = {
                                0: 'Egresos',
                                1: '',
                                2: '',
                                #3: ''
                            }
                            est.append(saldo)
                        saldo = {
                            0: move.account_id.name,
                            1: balance,
                            #2: acumuladoe,
                            2: 'E'
                        }
                        egresos += balance
                        est.append(saldo)

            saldo = {
                0: 'Suma Egresos',
                1: egresos,
                2: '',
                #3: ''
            }
            est.append(saldo)

#__________________________________________________Variable de formato de consulta____________________________________________________________#
        com = {}
        if reporte.reporte == 'est':
            report = 'Estado de resultados'
        elif reporte.reporte == 'bal':
            report = 'Balance General'
        elif reporte.reporte == 'com':
            report = 'Balanza de comprobacion'

        if reporte.reporte == 'bal':
            com[0] = {
                0: report + " " + reporte.periodo.name,
                1: reporte.periodo.name,
                2: company
            }
        elif reporte.reporte == 'est':
            com[0] = {
                0:
                report + " " + self._get_mes(cr, uid, reporte.mes, context) +
                ' ' + reporte.periodo.name,
                1:
                company
            }
        else:
            com[0] = {
                0: report,
                1: self._get_mes(cr, uid, reporte.mes, context),
                2: reporte.periodo.name,
                3: company
            }


# #______________________________________________________Creacion del archivo PDF_______________________________________________________________#

#______________________________________________________Creacion del archivo XLS_______________________________________________________________#
        libro = xlwt.Workbook()
        libro1 = libro.add_sheet("Consulta")
        book = xlwt.Workbook()
        sheet = book.add_sheet("Reporte")
        txt = "Fila %s, Columna %s"
        style = xlwt.XFStyle()

        # font
        font = xlwt.Font()
        font.bold = True
        style.font = font

        # borders
        borders = xlwt.Borders()
        borders.bottom = xlwt.Borders.DASHED
        style.borders = borders

        size = 48
        im = Image.open(StringIO.StringIO(base64.b64decode(logo)))
        im.thumbnail(size, Image.ANTIALIAS)
        im.convert("RGB").save('tmp/logo.bmp')
        sheet.insert_bitmap('tmp/logo.bmp', 0, 0, 0, 0)  # )

        if reporte.reporte == 'bal':
            cabeceras = {0: 'Activo', 1: '-', 2: 'Pasivo'}
            for num in range(len(bal)):
                row = sheet.row(num)
                fila = bal[num]
                for col in range(0, 6):
                    colunm = sheet.col(col)
                    if col == 2:
                        colunm.width = 32 * 30
                    else:
                        colunm.width = 256 * 30
                if num == 0:
                    fila = com[num]
                    for index, col in enumerate(fila):
                        comp = com[0]
                        if index == 0:
                            row.write(
                                index + 1, comp[col],
                                xlwt.easyxf(
                                    "font: name Arial, height 280, color blue, bold on; align: wrap on, vert centre, horiz center"
                                ))  #pattern: pattern solid, fore_color white;
                            row.height_mismatch = True
                            row.height = 90 * 30
                        elif index == 2:
                            row.write(
                                index + 1, comp[col],
                                xlwt.easyxf(
                                    "font: name Arial, height 280, color blue, bold on; align: wrap on, vert centre, horiz center"
                                ))
                            row.height_mismatch = True
                            row.height = 90 * 30
                else:
                    for index, col in enumerate(fila):
                        if num == 1:
                            cab = cabeceras[index]
                            if index == 1:
                                cab = cabeceras[index + 1]
                                row.write(index + 2, cab, style=style)
                            elif index == 0:
                                row.write(index, cab, style=style)
                        elif num > 1:
                            fila = bal[num - 2]
                            celda = fila[index]
                            #for index, col in enumerate(fila):
                            #raise osv.except_osv(index, fila)
                            if index < 2:
                                if 'Activo' in str(celda):
                                    row.write(index, celda, style=style)
                                else:
                                    row.write(index, celda)
                if num + 2 == len(bal):
                    row = sheet.row(num + 2)
                    for index, col in enumerate(fila):
                        fila = bal[num]
                        celda = fila[index]
                        if index < 2:
                            row.write(index, celda)

                if num + 1 == len(bal):
                    row = sheet.row(num + 2)
                    for index, col in enumerate(fila):
                        fila = bal[num]
                        celda = fila[index]
                        row = sheet.row(32)
                        if index < 2:
                            if index == 0:
                                row.write(index, celda, style=style)
                            else:
                                row.write(index, celda)

            for num in range(len(bal1)):
                row = sheet.row(num + 2)
                fila = bal1[num]
                for index, col in enumerate(fila):
                    fila = bal1[num]
                    celda = fila[index]
                    if index < 2:
                        if 'Suma' in str(fila[0]):
                            row = sheet.row(32)
                            if index == 0:
                                row.write(index + 3, celda, style=style)
                            else:
                                row.write(index + 3, celda)
                        elif 'Pasivo' in str(celda) or 'Capital' in str(celda):
                            row.write(index + 3, celda, style=style)
                        else:
                            row.write(index + 3, celda)

        elif reporte.reporte == 'est':
            cabeceras = {0: 'Nombre', 1: 'Balance', 2: 'Acumulado'}
            for num in range(len(est)):
                row = sheet.row(num)
                fila = est[num]
                for col in range(0, 6):
                    colunm = sheet.col(col)
                    #if col == 2:
                    #    colunm.width = 32 * 30
                    #else:
                    colunm.width = 256 * 30
                if num == 0:
                    fila = com[num]
                    for index, col in enumerate(fila):
                        comp = com[0]
                        if index == 0:
                            row.write(
                                index + 1, comp[col],
                                xlwt.easyxf(
                                    "font: name Arial, height 280, color blue, bold on; align: wrap on, vert centre, horiz center"
                                ))  #pattern: pattern solid, fore_color white;
                            row.height_mismatch = True
                            row.height = 90 * 30
                        elif index == 1:
                            row.write(
                                index + 1, comp[col],
                                xlwt.easyxf(
                                    "font: name Arial, height 280, color blue, bold on; align: wrap on, vert centre, horiz center"
                                ))
                            row.height_mismatch = True
                            row.height = 90 * 30
                else:
                    for index, col in enumerate(cabeceras):
                        if num == 1:
                            cab = cabeceras[index]
                            #if index == 1:
                            #    cab = cabeceras[index+1]
                            #    row.write(index+2, cab, style=style)
                            #elif index == 0:
                            if index < 2:
                                row.write(index, cab, style=style)
                        elif num > 1:
                            if index < 2:
                                fila = est[num - 2]
                                celda = fila[index]
                            #for index, col in enumerate(fila):
                    #raise osv.except_osv(index, fila)
                            if index < 2:
                                if 'Ingreso' in str(celda) or 'Egreso' in str(
                                        celda):
                                    row.write(index, celda, style=style)
                                else:
                                    row.write(index, celda)
                if num + 2 == len(est):
                    row = sheet.row(num + 2)
                    for index, col in enumerate(fila):
                        fila = est[num]
                        celda = fila[index]
                        if index < 2:
                            row.write(index, celda)

                if num + 1 == len(est):
                    row = sheet.row(num + 2)
                    for index, col in enumerate(fila):
                        fila = est[num]
                        celda = fila[index]
                        if index < 2:
                            if index == 0:
                                row.write(index, celda, style=style)
                            else:
                                row.write(index, celda)

        elif reporte.reporte == 'com':
            if reporte.mensual == True:
                for num in range(registros):
                    row = sheet.row(num)
                    fila = resultado[num]
                    for col in range(0, 7):
                        colunm = sheet.col(col)
                        #if col == 2:
                        #    colunm.width = 32 * 30
                        #else:
                        colunm.width = 256 * 30
                    if num == 0:
                        fila = com[num]
                        for index, col in enumerate(fila):
                            comp = com[0]
                            if index == 0:
                                row.write(
                                    index + 1, comp[col],
                                    xlwt.easyxf(
                                        "font: name Arial, height 280, color blue, bold on; align: wrap on, vert centre, horiz center"
                                    )
                                )  #pattern: pattern solid, fore_color white;
                                row.height_mismatch = True
                                row.height = 90 * 30
                            elif index == 2:
                                row.write(
                                    index + 1, comp[col],
                                    xlwt.easyxf(
                                        "font: name Arial, height 280, color blue, bold on; align: wrap on, vert centre, horiz center"
                                    ))
                                row.height_mismatch = True
                                row.height = 90 * 30
                    else:
                        for index, col in enumerate(fila):
                            if num == 1:
                                cab = cabeceras[index]
                                row.write(index, cab)
                            #row.write(index, cab[0])
                            elif num > 1:
                                fila = resultado[num - 2]
                                celda = fila[index]
                                row.write(index, celda)
                    if num + 2 == registros:
                        row = sheet.row(num + 2)
                        for index, col in enumerate(fila):
                            fila = resultado[num]
                            celda = fila[index]
                            row.write(index, celda)
                    if num + 1 == registros:
                        row = sheet.row(num + 2)
                        for index, col in enumerate(fila):
                            fila = resultado[num]
                            celda = fila[index]
                            row.write(index, celda)
            else:
                for num in range(registros):
                    row = libro1.row(num)
                    fila = resultado[num]
                    if num == 0:
                        fila = com[num]
                        for index, col in enumerate(fila):
                            colunm = libro1.col(col)
                            colunm.width = 256 * 30
                        comp = com[0]
                        row.write(index, comp[col])
                    else:
                        for index, col in enumerate(fila):
                            if num == 1:
                                cab = cabeceras[index]
                                row.write(index, cab)
                        #row.write(index, cab[0])
                            elif num > 1:
                                fila = resultado[num - 2]
                                celda = fila[index]
                                row.write(index, celda)
                    if num + 2 == registros:
                        row = libro1.row(num + 2)
                        for index, col in enumerate(fila):
                            fila = resultado[num]
                            celda = fila[index]
                            row.write(index, celda)
                    if num + 1 == registros:
                        row = libro1.row(num + 2)
                        for index, col in enumerate(fila):
                            fila = resultado[num]
                            celda = fila[index]
                            row.write(index, celda)

            # for num in range(len(bal1)):
            #     row = sheet.row(num+2)
            #     fila = bal1[num]
            #     for index, col in enumerate(fila):
            #         fila = bal1[num]
            #         celda = fila[index]
            #         if index < 2:
            #             if 'Suma' in str(fila[0]):
            #                 row = sheet.row(32)
            #                 if index == 0:
            #                     row.write(index + 3, celda, style=style)
            #                 else:
            #                     row.write(index + 3, celda)
            #             elif 'Pasivo' in str(celda) or 'Capital' in str(celda):
            #                 row.write(index + 3, celda, style=style)
            #             else:
            #                 row.write(index+3, celda)

        fp = StringIO.StringIO()
        book.save(fp)
        fp.seek(0)
        data = fp.read()
        fp.close()
        out = base64.encodestring(data)
        book.save('tmp/Excel.pdf')

        this = self.browse(cr, uid, ids, context=context)[0]

        if 'Balance General' in report:
            filename = report + " " + reporte.periodo.name
        else:
            filename = report + " " + self._get_mes(
                cr, uid, reporte.mes, context) + " " + reporte.periodo.name

        extension = "xls"  #this.format

        name = "%s.%s" % (filename, extension)
        this.write({'binario': out, 'name': name})

    def _get_mes(self, cr, uid, mes, context=None):

        meses = [
            'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio',
            'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'
        ]

        mes_act = meses[int(mes) - 1]

        return mes_act

    _columns = {
        'reporte':
        fields.selection([('bal', 'Balance General'),
                          ('com', 'Balanza de comprobacion'),
                          ('est', 'Estados de resultados')],
                         'Reporte',
                         required=True,
                         help="Escoger el informe a exportar"),
        'nivel':
        fields.selection([('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'),
                          ('5', '5'), ('6', '6')],
                         'Nivel',
                         help="Escoger el nivel",
                         size=30),
        'periodo':
        fields.many2one('account.fiscalyear', 'Periodo'),
        'movimiento':
        fields.selection([('1', 'Todos los movimientos'),
                          ('2', 'Todos los movimientos asentados')],
                         'Movimientos'),
        'cero':
        fields.boolean(
            'Cuentas cero',
            help="Marcar si se desea visualizar cuentas con saldo cero"),
        'mensual':
        fields.boolean(
            'Mensual',
            help="Marcar si se desea visualizar un mes en especifico"),
        'mes':
        fields.selection([('1', 'Enero'), ('2', 'Febrero'), ('3', 'Marzo'),
                          ('4', 'Abril'), ('5', 'Mayo'), ('6', 'Junio'),
                          ('7', 'Julio'), ('8', 'Agosto'), ('9', 'Septiembre'),
                          ('10', 'Octubre'), ('11', 'Noviembre'),
                          ('12', 'Diciembre')],
                         'Mes',
                         help="Escoger el mes"),
        'todos':
        fields.boolean(
            'Asientos',
            help="Marcar si se desea visualizar todos los asientos"),
        'deb_cre':
        fields.boolean(
            'Debito/Credito',
            help="Marcar si se desea visualizar la columna debito y credito"),
        #'archivo': fields.text('Archivo', size=30,help="Marcar si se desea visualizar un mes en especifico"),
        'binario':
        fields.binary('Label', filters='*.xml', filename='Excel'),
        'name':
        fields.char('File Name', readonly=True),
        #'bpdf': fields.binary('Label',filters='*.xml', filename='PDF'),
        #'namepdf': fields.char('File Name', readonly=True),
    }

    _defaults = {
        'nivel': '1',
        'periodo': '2',
        'cero': False,
        'mensual': True,
        'mes': '1',
        'todos': False,
        'deb_cre': False,
        'movimiento': '1',
        #'archivo': 'Excel.csv',
        #'binario': '/tmp/excel.csv',
    }
Example #51
0
    def onchange_logis_company(self, cr, uid, ids, logistic_company_id, context=None):
        res = {}
        if logistic_company_id:
            logistic_company = self.pool.get('logistic.company').browse(cr, uid, logistic_company_id, context=context)
            res =  {'value': {'ship_company_code': logistic_company.ship_company_code,'sale_account_id':logistic_company.ship_account_id.id}}
        return res
    
    def _get_logis_company(self, cr, uid, context=None):
        if context is None:
            context = {}
        user_rec = self.pool.get('res.users').browse(cr ,uid, uid, context)
        logis_company = self.pool.get('logistic.company').search(cr, uid, [])
        return logis_company and logis_company[0] or False

    _columns= {
        'logis_company': fields.many2one('logistic.company', 'Logistic Company', help='Name of the Logistics company providing the shipper services.'),
        'ship_company_code': fields.selection(_get_company_code, 'Ship Company', method=True, size=64),
        'rate_selection': fields.selection([('rate_card', 'Rate Card'), ('rate_request', 'Rate Request')], 'Ship Rate Method'),
        'partner_order_id': fields.many2one('res.partner', 'Ordering Contact', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="The name and address of the contact who requested the order or quotation."),
    }

    _defaults = {
        'partner_order_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['order_contact'])['order_contact'],
        'logis_company': _get_logis_company,
    }

    def onchange_partner_id(self, cr, uid, ids, part, context=None):
        addr = {}
        if part:
            addr = super(sale_order, self).onchange_partner_id(cr, uid, ids, part, context)
            addr['value'].update({'partner_order_id': part})
Example #52
0
class sale_order(osv.Model):
    _inherit = 'sale.order'
    _columns = {
        'carrier_id':
        fields.many2one(
            "delivery.carrier",
            string="Delivery Method",
            help=
            "Complete this field if you plan to invoice the shipping based on picking."
        ),
    }

    def onchange_partner_id(self, cr, uid, ids, part, context=None):
        result = super(sale_order, self).onchange_partner_id(cr,
                                                             uid,
                                                             ids,
                                                             part,
                                                             context=context)
        if part:
            dtype = self.pool.get('res.partner').browse(
                cr, uid, part, context=context).property_delivery_carrier.id
            # TDE NOTE: not sure the aded 'if dtype' is valid
            if dtype:
                result['value']['carrier_id'] = dtype
        return result

    def _delivery_unset(self, cr, uid, ids, context=None):
        sale_obj = self.pool['sale.order.line']
        line_ids = sale_obj.search(cr,
                                   uid, [('order_id', 'in', ids),
                                         ('is_delivery', '=', True)],
                                   context=context)
        sale_obj.unlink(cr, uid, line_ids, context=context)

    def delivery_set(self, cr, uid, ids, context=None):
        line_obj = self.pool.get('sale.order.line')
        grid_obj = self.pool.get('delivery.grid')
        carrier_obj = self.pool.get('delivery.carrier')
        acc_fp_obj = self.pool.get('account.fiscal.position')
        self._delivery_unset(cr, uid, ids, context=context)
        currency_obj = self.pool.get('res.currency')
        line_ids = []
        for order in self.browse(cr, uid, ids, context=context):
            grid_id = carrier_obj.grid_get(cr, uid, [order.carrier_id.id],
                                           order.partner_shipping_id.id)
            if not grid_id:
                raise UserError(_('No grid matching for this carrier!'))

            if order.state not in ('draft', 'sent'):
                raise UserError(
                    _('The order state have to be draft to add delivery lines.'
                      ))

            grid = grid_obj.browse(cr, uid, grid_id, context=context)

            taxes = grid.carrier_id.product_id.taxes_id
            fpos = order.fiscal_position_id or False
            taxes_ids = acc_fp_obj.map_tax(cr, uid, fpos, taxes)
            price_unit = grid_obj.get_price(cr, uid, grid.id, order,
                                            time.strftime('%Y-%m-%d'), context)
            if order.company_id.currency_id.id != order.pricelist_id.currency_id.id:
                price_unit = currency_obj.compute(
                    cr,
                    uid,
                    order.company_id.currency_id.id,
                    order.pricelist_id.currency_id.id,
                    price_unit,
                    context=dict(context or {}, date=order.date_order))
            #create the sale order line
            line_id = line_obj.create(
                cr,
                uid, {
                    'order_id': order.id,
                    'name': grid.carrier_id.name,
                    'product_uom_qty': 1,
                    'product_uom': grid.carrier_id.product_id.uom_id.id,
                    'product_id': grid.carrier_id.product_id.id,
                    'price_unit': price_unit,
                    'tax_id': [(6, 0, taxes_ids)],
                    'is_delivery': True
                },
                context=context)
            line_ids.append(line_id)
        return line_ids
Example #53
0
                  except UserError, e:
                    # no suitable delivery method found, probably configuration error
                    _logger.info("Carrier %s: %s", carrier.name, e.name)
                    price = 0.0
              else:
                  price = 0.0
            res[carrier.id] = {
                'price': price,
                'available': available
            }
        return res

    _columns = {
        'name': fields.char('Delivery Method', required=True, translate=True),
        'sequence': fields.integer('Sequence', help="Determine the display order"),
        'partner_id': fields.many2one('res.partner', 'Transport Company', required=True, help="The partner that is doing the delivery service."),
        'product_id': fields.many2one('product.product', 'Delivery Product', required=True),
        'grids_id': fields.one2many('delivery.grid', 'carrier_id', 'Delivery Grids'),
        'available' : fields.function(get_price, string='Available',type='boolean', multi='price',
            help="Is the carrier method possible with the current order."),
        'price' : fields.function(get_price, string='Price', multi='price'),
        'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the delivery carrier without removing it."),
        'normal_price': fields.float('Normal Price', help="Keep empty if the pricing depends on the advanced pricing per destination"),
        'free_if_more_than': fields.boolean('Free If Order Total Amount Is More Than', help="If the order is more expensive than a certain amount, the customer can benefit from a free shipping"),
        'amount': fields.float('Amount', help="Amount of the order to benefit from a free shipping, expressed in the company currency"),
        'use_detailed_pricelist': fields.boolean('Advanced Pricing per Destination', help="Check this box if you want to manage delivery prices that depends on the destination, the weight, the total of the order, etc."),
        'pricelist_ids': fields.one2many('delivery.grid', 'carrier_id', 'Advanced Pricing'),
    }

    _defaults = {
        'active': 1,
Example #54
0
class event_event(osv.osv):
    _inherit = "event.event"

    def _tz_get(self, cr, uid, context=None):
        # put POSIX 'Etc/*' entries at the end to avoid confusing users - see bug 1086728
        return [(tz, tz)
                for tz in sorted(pytz.all_timezones,
                                 key=lambda tz: tz
                                 if not tz.startswith('Etc/') else '_')]

    def _count_tracks(self, cr, uid, ids, field_name, arg, context=None):
        return {
            event.id: len(event.track_ids)
            for event in self.browse(cr, uid, ids, context=context)
        }

    def _get_tracks_tag_ids(self,
                            cr,
                            uid,
                            ids,
                            field_names,
                            arg=None,
                            context=None):
        res = dict.fromkeys(ids, [])
        for event in self.browse(cr, uid, ids, context=context):
            for track in event.track_ids:
                res[event.id] += [tag.id for tag in track.tag_ids]
            res[event.id] = list(set(res[event.id]))
        return res

    _columns = {
        'tag_ids':
        fields.many2many('event.tag', string='Tags'),
        'track_ids':
        fields.one2many('event.track', 'event_id', 'Tracks'),
        'sponsor_ids':
        fields.one2many('event.sponsor', 'event_id', 'Sponsorships'),
        'blog_id':
        fields.many2one('blog.blog', 'Event Blog'),
        'show_track_proposal':
        fields.boolean('Talks Proposals'),
        'show_tracks':
        fields.boolean('Multiple Tracks'),
        'show_blog':
        fields.boolean('News'),
        'count_tracks':
        fields.function(_count_tracks, type='integer', string='Tracks'),
        'tracks_tag_ids':
        fields.function(_get_tracks_tag_ids,
                        type='one2many',
                        relation='event.track.tag',
                        string='Tags of Tracks'),
        'allowed_track_tag_ids':
        fields.many2many('event.track.tag',
                         string='Accepted Tags',
                         help="List of available tags for track proposals."),
        'timezone_of_event':
        fields.selection(_tz_get, 'Event Timezone', size=64),
    }

    _defaults = {
        'show_track_proposal':
        False,
        'show_tracks':
        False,
        'show_blog':
        False,
        'timezone_of_event':
        lambda self, cr, uid, c: self.pool.get('res.users').browse(
            cr, uid, uid, c).tz,
    }

    def _get_new_menu_pages(self, cr, uid, event, context=None):
        context = context or {}
        result = super(event_event, self)._get_new_menu_pages(cr,
                                                              uid,
                                                              event,
                                                              context=context)
        if event.show_tracks:
            result.append((_('Talks'), '/event/%s/track' % slug(event)))
            result.append((_('Agenda'), '/event/%s/agenda' % slug(event)))
        if event.blog_id:
            result.append((_('News'), '/blogpost' + slug(event.blog_ig)))
        if event.show_track_proposal:
            result.append((_('Talk Proposals'),
                           '/event/%s/track_proposal' % slug(event)))
        return result
Example #55
0
    def _get_icon_image(self, cr, uid, ids, field_name=None, arg=None, context=None):
        res = dict.fromkeys(ids, '')
        for module in self.browse(cr, uid, ids, context=context):
            path = addons.get_module_resource(module.name, 'static', 'src', 'img', 'icon.png')
            if path:
                image_file = tools.file_open(path, 'rb')
                try:
                    res[module.id] = image_file.read().encode('base64')
                finally:
                    image_file.close()
        return res

    _columns = {
        'name': fields.char("Technical Name", size=128, readonly=True, required=True, select=True),
        'category_id': fields.many2one('ir.module.category', 'Category', readonly=True, select=True),
        'shortdesc': fields.char('Module Name', size=64, readonly=True, translate=True),
        'summary': fields.char('Summary', size=64, readonly=True, translate=True),
        'description': fields.text("Description", readonly=True, translate=True),
        'description_html': fields.function(_get_desc, string='Description HTML', type='html', method=True, readonly=True),
        'author': fields.char("Author", size=128, readonly=True),
        'maintainer': fields.char('Maintainer', size=128, readonly=True),
        'contributors': fields.text('Contributors', readonly=True),
        'website': fields.char("Website", size=256, readonly=True),

        # attention: Incorrect field names !!
        #   installed_version refers the latest version (the one on disk)
        #   latest_version refers the installed version (the one in database)
        #   published_version refers the version available on the repository
        'installed_version': fields.function(_get_latest_version, string='Latest Version', type='char'),
        'latest_version': fields.char('Installed Version', size=64, readonly=True),
Example #56
0
class event_track(osv.osv):
    _name = "event.track"
    _description = 'Event Tracks'
    _order = 'priority, date'
    _inherit = ['mail.thread', 'ir.needaction_mixin', 'website.seo.metadata']

    def _website_url(self, cr, uid, ids, field_name, arg, context=None):
        res = dict.fromkeys(ids, '')
        for track in self.browse(cr, uid, ids, context=context):
            res[track.id] = "/event/%s/track/%s" % (slug(
                track.event_id), slug(track))
        return res

    _columns = {
        'name':
        fields.char('Track Title', required=True, translate=True),
        'user_id':
        fields.many2one('res.users', 'Responsible'),
        'speaker_ids':
        fields.many2many('res.partner', string='Speakers'),
        'tag_ids':
        fields.many2many('event.track.tag', string='Tags'),
        'stage_id':
        fields.many2one('event.track.stage', 'Stage'),
        'description':
        fields.html('Track Description', translate=True),
        'date':
        fields.datetime('Track Date'),
        'duration':
        fields.float('Duration', digits=(16, 2)),
        'location_id':
        fields.many2one('event.track.location', 'Location'),
        'event_id':
        fields.many2one('event.event', 'Event', required=True),
        'color':
        fields.integer('Color Index'),
        'priority':
        fields.selection([('3', 'Low'), ('2', 'Medium (*)'),
                          ('1', 'High (**)'), ('0', 'Highest (***)')],
                         'Priority',
                         required=True),
        'website_published':
        fields.boolean('Available in the website'),
        'website_url':
        fields.function(_website_url, string="Website url", type="char"),
        'image':
        fields.related('speaker_ids', 'image', type='binary', readonly=True)
    }

    def set_priority(self, cr, uid, ids, priority, context={}):
        return self.write(cr, uid, ids, {'priority': priority})

    def _default_stage_id(self, cr, uid, context={}):
        stage_obj = self.pool.get('event.track.stage')
        ids = stage_obj.search(cr, uid, [], context=context)
        return ids and ids[0] or False

    _defaults = {
        'user_id': lambda self, cr, uid, ctx: uid,
        'website_published': lambda self, cr, uid, ctx: False,
        'duration': lambda *args: 1.5,
        'stage_id': _default_stage_id,
        'priority': '2'
    }

    def _read_group_stage_ids(self,
                              cr,
                              uid,
                              ids,
                              domain,
                              read_group_order=None,
                              access_rights_uid=None,
                              context=None):
        stage_obj = self.pool.get('event.track.stage')
        result = stage_obj.name_search(cr, uid, '', context=context)
        return result, {}

    _group_by_full = {
        'stage_id': _read_group_stage_ids,
    }
ACC_FISC_ALLOC_RULE_COLS_TMPL = {

    # Note: This are template style fields.
    # For nontemplate fields you might add aditional constraints to specific nontemplate fields (eg. company_id).
    # The chain method from itertools updates fields. Consider using this from within the nontemplate class when adding
    # new fields.

    # --- GENERAL SECTION ---

    'name': fields.char('Name', required=True),
    'description': fields.char('Description'),
    # This fiscal domain will narrow down the available fiscal attributes / fiscal allocations.
    # It should help clustering and reducing complexity. Rules are applied *additionally*
    # preserving the result (reed: taxes applied) of previous iterations.
    # However it is optional. You can construct more complex "cross-domain" rules leaving it empty.
    'fiscal_domain_id': fields.many2one('account.fiscal.domain', 'Fiscal Domain', required=True, select=True),
    'is_account_allocation': fields.boolean(u'Account Allocation?'),

    # --- CRITERION SECTION ---

    '{0}_country'.format(ATTR_USE_DOM_COMPANY[0]): fields.many2one('res.country', 'Country'),
    '{0}_state'.format(ATTR_USE_DOM_COMPANY[0]): fields.many2one(
        'res.country.state', 'State',
        domain="[('country_id','=',{0}_country)]".format(ATTR_USE_DOM_COMPANY[0])),
    'to_{0}_country'.format(ATTR_USE_DOM_PINVOICE[0]): fields.many2one(
        'res.country', 'Country'),
    'to_{0}_state'.format(ATTR_USE_DOM_PINVOICE[0]): fields.many2one(
        'res.country.state', 'State',
        domain="[('country_id','=',to_{0}_country)]".format(ATTR_USE_DOM_PINVOICE[0])),
    'to_{0}_country'.format(ATTR_USE_DOM_PSHIPPER[0]): fields.many2one(
        'res.country', 'Country'),
Example #58
0
     clock_ids = self.pool.get("hr.clock").search(cr, uid, [], context=context)
     clock_ids_exist = []
     try:
         for order in self.browse(cr, uid, ids, context=context):
             emp_code = order.employee_id.emp_code
             for clock_id in clock_ids:
                 emps_clock = clock_sync_obj.clock_emps_get(cr, uid, clock_id, [emp_code], context=context)
                 if emps_clock:
                     clock_ids_exist.append(clock_id)
             resu[order.id] = clock_ids_exist
     except Exception,e:
         traceback.print_exc()
         pass 
     return resu
 _columns = {
     'employee_id': fields.many2one('hr.employee',  'Employee', required=True, select=True),
     'department_id':fields.related('employee_id','department_id', type='many2one', relation='hr.department', string='Department', store=True),
     'job_id':fields.related('employee_id','job_id', type='many2one', relation='hr.job', string='Title', store=True),
     'emp_code':fields.related('employee_id','emp_code', type='char', string='Employee Code', store=True),
     'mobile_phone':fields.related('employee_id','mobile_phone', type='char', string='Work Mobile', store=True),
     'borrow_money_residual':fields.related('employee_id','money_residual', type='float', string='Borrowed residual', readonly=True),
     
     'dimmission_reason':fields.text('Dimission Reason', required=True),
     'advice_to_company':fields.text('Advice to company'),
     'employment_start':fields.date('Employment Started'),
     'date_request':fields.date('Request Date', required=True),
     'date_done':fields.date('Done Date', required=False, readonly=True),
     
     'approve_ids': fields.one2many('hr.dimission.item', 'dimission_id', 'Approvals', domain=[('type','=','approve')]),
     'transfer_ids': fields.one2many('hr.dimission.item', 'dimission_id', 'Transfers', domain=[('type','=','transfer')]),
     
Example #59
0
        return self.write(cr, uid, id, {"file_db_store": value}, context=context)

    _columns = {
        "name": fields.char("Image Title", size=64),
        "filename": fields.char("Filename", size=64),
        "extension": fields.char("file extension", oldname="extention"),
        "link": fields.boolean(
            "Link?", help="Images can be linked from files on " "your file system or remote (Preferred)"
        ),
        "file_db_store": fields.binary("Image stored in database"),
        "file": fields.function(
            _get_image, fnct_inv=_set_image, type="binary", string="File", filters="*.png,*.jpg,*.gif"
        ),
        "url": fields.char("File Location"),
        "url_big": fields.char("File Location Image Size Big"),
        "url_medium": fields.char("File Location Image Size Medium"),
        "url_small": fields.char("File Location Image Size Small"),
        "comments": fields.text("Comments"),
        "product_id": fields.many2one("product.product", "Product"),
    }

    _defaults = {"link": True}

    _sql_constraints = [
        (
            "uniq_name_product_id",
            "UNIQUE(product_id, name)",
            _("A product can have only one " "image with the same name"),
        )
    ]
Example #60
0
class sale_order(osv.osv):
    _inherit = "sale.order"
    
    def copy(self, cr, uid, id, default=None, context=None):
        if not default:
            default = {}
        default.update({
            'shipped': False,
            'picking_ids': [],
        })
        return super(sale_order, self).copy(cr, uid, id, default, context=context)
    
    def shipping_policy_change(self, cr, uid, ids, policy, context=None):
        if not policy:
            return {}
        inv_qty = 'order'
        if policy == 'prepaid':
            inv_qty = 'order'
        elif policy == 'picking':
            inv_qty = 'procurement'
        return {'value': {'invoice_quantity': inv_qty}}

    def write(self, cr, uid, ids, vals, context=None):
        if vals.get('order_policy', False):
            if vals['order_policy'] == 'prepaid':
                vals.update({'invoice_quantity': 'order'})
            elif vals['order_policy'] == 'picking':
                vals.update({'invoice_quantity': 'procurement'})
        return super(sale_order, self).write(cr, uid, ids, vals, context=context)

    def create(self, cr, uid, vals, context=None):
        if vals.get('order_policy', False):
            if vals['order_policy'] == 'prepaid':
                vals.update({'invoice_quantity': 'order'})
            if vals['order_policy'] == 'picking':
                vals.update({'invoice_quantity': 'procurement'})
        order =  super(sale_order, self).create(cr, uid, vals, context=context)
        return order

    # This is False
    def _picked_rate(self, cr, uid, ids, name, arg, context=None):
        if not ids:
            return {}
        res = {}
        tmp = {}
        for id in ids:
            tmp[id] = {'picked': 0.0, 'total': 0.0}
        cr.execute('''SELECT
                p.sale_id as sale_order_id, sum(m.product_qty) as nbr, mp.state as procurement_state, m.state as move_state, p.type as picking_type
            FROM
                stock_move m
            LEFT JOIN
                stock_picking p on (p.id=m.picking_id)
            LEFT JOIN
                procurement_order mp on (mp.move_id=m.id)
            WHERE
                p.sale_id IN %s GROUP BY m.state, mp.state, p.sale_id, p.type''', (tuple(ids),))

        for item in cr.dictfetchall():
            if item['move_state'] == 'cancel':
                continue

            if item['picking_type'] == 'in':#this is a returned picking
                tmp[item['sale_order_id']]['total'] -= item['nbr'] or 0.0 # Deducting the return picking qty
                if item['procurement_state'] == 'done' or item['move_state'] == 'done':
                    tmp[item['sale_order_id']]['picked'] -= item['nbr'] or 0.0
            else:
                tmp[item['sale_order_id']]['total'] += item['nbr'] or 0.0
                if item['procurement_state'] == 'done' or item['move_state'] == 'done':
                    tmp[item['sale_order_id']]['picked'] += item['nbr'] or 0.0

        for order in self.browse(cr, uid, ids, context=context):
            if order.shipped:
                res[order.id] = 100.0
            else:
                res[order.id] = tmp[order.id]['total'] and (100.0 * tmp[order.id]['picked'] / tmp[order.id]['total']) or 0.0
        return res
    
    _columns = {
          'state': fields.selection([
            ('draft', 'Draft Quotation'),
            ('sent', 'Quotation Sent'),
            ('cancel', 'Cancelled'),
            ('waiting_date', 'Waiting Schedule'),
            ('progress', 'Sales Order'),
            ('manual', 'Sale to Invoice'),
            ('shipping_except', 'Shipping Exception'),
            ('invoice_except', 'Invoice Exception'),
            ('done', 'Done'),
            ], 'Status', readonly=True,help="Gives the status of the quotation or sales order.\
              \nThe exception status is automatically set when a cancel operation occurs \
              in the invoice validation (Invoice Exception) or in the picking list process (Shipping Exception).\nThe 'Waiting Schedule' status is set when the invoice is confirmed\
               but waiting for the scheduler to run on the order date.", select=True),
        'incoterm': fields.many2one('stock.incoterms', 'Incoterm', help="International Commercial Terms are a series of predefined commercial terms used in international transactions."),
        'picking_policy': fields.selection([('direct', 'Deliver each product when available'), ('one', 'Deliver all products at once')],
            'Shipping Policy', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
            help="""Pick 'Deliver each product when available' if you allow partial delivery."""),
        'order_policy': fields.selection([
                ('manual', 'On Demand'),
                ('picking', 'On Delivery Order'),
                ('prepaid', 'Before Delivery'),
            ], 'Create Invoice', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
            help="""On demand: A draft invoice can be created from the sales order when needed. \nOn delivery order: A draft invoice can be created from the delivery order when the products have been delivered. \nBefore delivery: A draft invoice is created from the sales order and must be paid before the products can be delivered."""),
        'picking_ids': fields.one2many('stock.picking.out', 'sale_id', 'Related Picking', readonly=True, help="This is a list of delivery orders that has been generated for this sales order."),
        'shipped': fields.boolean('Delivered', readonly=True, help="It indicates that the sales order has been delivered. This field is updated only after the scheduler(s) have been launched."),
        'picked_rate': fields.function(_picked_rate, string='Picked', type='float'),
        'invoice_quantity': fields.selection([('order', 'Ordered Quantities'), ('procurement', 'Shipped Quantities')], 'Invoice on', 
                                             help="The sales order will automatically create the invoice proposition (draft invoice).\
                                              You have to choose  if you want your invoice based on ordered ", required=True, readonly=True, states={'draft': [('readonly', False)]}),
    }
    _defaults = {
             'picking_policy': 'direct',
             'order_policy': 'manual',
             'invoice_quantity': 'order',
         }

    # Form filling
    def unlink(self, cr, uid, ids, context=None):
        sale_orders = self.read(cr, uid, ids, ['state'], context=context)
        unlink_ids = []
        for s in sale_orders:
            if s['state'] in ['draft', 'cancel']:
                unlink_ids.append(s['id'])
            else:
                raise osv.except_osv(_('Invalid Action!'), _('In order to delete a confirmed sales order, you must cancel it.\nTo do so, you must first cancel related picking for delivery orders.'))

        return osv.osv.unlink(self, cr, uid, unlink_ids, context=context)

    def action_view_delivery(self, cr, uid, ids, context=None):
        '''
        This function returns an action that display existing delivery orders of given sales order ids. It can either be a in a list or in a form view, if there is only one delivery order to show.
        '''
        mod_obj = self.pool.get('ir.model.data')
        act_obj = self.pool.get('ir.actions.act_window')

        result = mod_obj.get_object_reference(cr, uid, 'stock', 'action_picking_tree')
        id = result and result[1] or False
        result = act_obj.read(cr, uid, [id], context=context)[0]
        #compute the number of delivery orders to display
        pick_ids = []
        for so in self.browse(cr, uid, ids, context=context):
            pick_ids += [picking.id for picking in so.picking_ids]
        #choose the view_mode accordingly
        if len(pick_ids) > 1:
            result['domain'] = "[('id','in',["+','.join(map(str, pick_ids))+"])]"
        else:
            res = mod_obj.get_object_reference(cr, uid, 'stock', 'view_picking_out_form')
            result['views'] = [(res and res[1] or False, 'form')]
            result['res_id'] = pick_ids and pick_ids[0] or False
        return result

    def action_invoice_create(self, cr, uid, ids, grouped=False, states=['confirmed', 'done', 'exception'], date_invoice = False, context=None):
        picking_obj = self.pool.get('stock.picking')
        res = super(sale_order,self).action_invoice_create( cr, uid, ids, grouped=grouped, states=states, date_invoice = date_invoice, context=context)
        for order in self.browse(cr, uid, ids, context=context):
            if order.order_policy == 'picking':
                picking_obj.write(cr, uid, map(lambda x: x.id, order.picking_ids), {'invoice_state': 'invoiced'})
        return res

    def action_cancel(self, cr, uid, ids, context=None):
        wf_service = netsvc.LocalService("workflow")
        if context is None:
            context = {}
        sale_order_line_obj = self.pool.get('sale.order.line')
        proc_obj = self.pool.get('procurement.order')
        for sale in self.browse(cr, uid, ids, context=context):
            for pick in sale.picking_ids:
                if pick.state not in ('draft', 'cancel'):
                    raise osv.except_osv(
                        _('Cannot cancel sales order!'),
                        _('You must first cancel all delivery order(s) attached to this sales order.'))
                if pick.state == 'cancel':
                    for mov in pick.move_lines:
                        proc_ids = proc_obj.search(cr, uid, [('move_id', '=', mov.id)])
                        if proc_ids:
                            for proc in proc_ids:
                                wf_service.trg_validate(uid, 'procurement.order', proc, 'button_check', cr)
            for r in self.read(cr, uid, ids, ['picking_ids']):
                for pick in r['picking_ids']:
                    wf_service.trg_validate(uid, 'stock.picking', pick, 'button_cancel', cr)
        return super(sale_order, self).action_cancel(cr, uid, ids, context=context)

    def action_wait(self, cr, uid, ids, context=None):
        res = super(sale_order, self).action_wait(cr, uid, ids, context=context)
        for o in self.browse(cr, uid, ids):
            noprod = self.test_no_product(cr, uid, o, context)
            if noprod and o.order_policy=='picking':
                self.write(cr, uid, [o.id], {'order_policy': 'manual'}, context=context)
        return res

    def procurement_lines_get(self, cr, uid, ids, *args):
        res = []
        for order in self.browse(cr, uid, ids, context={}):
            for line in order.order_line:
                if line.procurement_id:
                    res.append(line.procurement_id.id)
        return res

    def date_to_datetime(self, cr, uid, userdate, context=None):
        """ Convert date values expressed in user's timezone to
        server-side UTC timestamp, assuming a default arbitrary
        time of 12:00 AM - because a time is needed.
    
        :param str userdate: date string in in user time zone
        :return: UTC datetime string for server-side use
        """
        # TODO: move to fields.datetime in server after 7.0
        user_date = datetime.strptime(userdate, DEFAULT_SERVER_DATE_FORMAT)
        if context and context.get('tz'):
            tz_name = context['tz']
        else:
            tz_name = self.pool.get('res.users').read(cr, SUPERUSER_ID, uid, ['tz'])['tz']
        if tz_name:
            utc = pytz.timezone('UTC')
            context_tz = pytz.timezone(tz_name)
            user_datetime = user_date + relativedelta(hours=12.0)
            local_timestamp = context_tz.localize(user_datetime, is_dst=False)
            user_datetime = local_timestamp.astimezone(utc)
            return user_datetime.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        return user_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT)

    # if mode == 'finished':
    #   returns True if all lines are done, False otherwise
    # if mode == 'canceled':
    #   returns True if there is at least one canceled line, False otherwise
    def test_state(self, cr, uid, ids, mode, *args):
        assert mode in ('finished', 'canceled'), _("invalid mode for test_state")
        finished = True
        canceled = False
        write_done_ids = []
        write_cancel_ids = []
        for order in self.browse(cr, uid, ids, context={}):
            for line in order.order_line:
                if (not line.procurement_id) or (line.procurement_id.state=='done'):
                    if line.state != 'done':
                        write_done_ids.append(line.id)
                else:
                    finished = False
                if line.procurement_id:
                    if (line.procurement_id.state == 'cancel'):
                        canceled = True
                        if line.state != 'exception':
                            write_cancel_ids.append(line.id)
        if write_done_ids:
            self.pool.get('sale.order.line').write(cr, uid, write_done_ids, {'state': 'done'})
        if write_cancel_ids:
            self.pool.get('sale.order.line').write(cr, uid, write_cancel_ids, {'state': 'exception'})

        if mode == 'finished':
            return finished
        elif mode == 'canceled':
            return canceled

    def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, context=None):
        return {
            'name': line.name,
            'origin': order.name,
            'date_planned': date_planned,
            'product_id': line.product_id.id,
            'product_qty': line.product_uom_qty,
            'product_uom': line.product_uom.id,
            'product_uos_qty': (line.product_uos and line.product_uos_qty)\
                    or line.product_uom_qty,
            'product_uos': (line.product_uos and line.product_uos.id)\
                    or line.product_uom.id,
            'location_id': order.shop_id.warehouse_id.lot_stock_id.id,
            'procure_method': line.type,
            'move_id': move_id,
            'company_id': order.company_id.id,
            'note': line.name,
            'property_ids': [(6, 0, [x.id for x in line.property_ids])],
        }

    def _prepare_order_line_move(self, cr, uid, order, line, picking_id, date_planned, context=None):
        location_id = order.shop_id.warehouse_id.lot_stock_id.id
        output_id = order.shop_id.warehouse_id.lot_output_id.id
        return {
            'name': line.name,
            'picking_id': picking_id,
            'product_id': line.product_id.id,
            'date': date_planned,
            'date_expected': date_planned,
            'product_qty': line.product_uom_qty,
            'product_uom': line.product_uom.id,
            'product_uos_qty': (line.product_uos and line.product_uos_qty) or line.product_uom_qty,
            'product_uos': (line.product_uos and line.product_uos.id)\
                    or line.product_uom.id,
            'product_packaging': line.product_packaging.id,
            'partner_id': line.address_allotment_id.id or order.partner_shipping_id.id,
            'location_id': location_id,
            'location_dest_id': output_id,
            'sale_line_id': line.id,
            'tracking_id': False,
            'state': 'draft',
            #'state': 'waiting',
            'company_id': order.company_id.id,
            'price_unit': line.product_id.standard_price or 0.0
        }

    def _prepare_order_picking(self, cr, uid, order, context=None):
        pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out')
        return {
            'name': pick_name,
            'origin': order.name,
            'date': self.date_to_datetime(cr, uid, order.date_order, context),
            'type': 'out',
            'state': 'auto',
            'move_type': order.picking_policy,
            'sale_id': order.id,
            'partner_id': order.partner_shipping_id.id,
            'note': order.note,
            'invoice_state': (order.order_policy=='picking' and '2binvoiced') or 'none',
            'company_id': order.company_id.id,
        }

    def ship_recreate(self, cr, uid, order, line, move_id, proc_id):
        # FIXME: deals with potentially cancelled shipments, seems broken (specially if shipment has production lot)
        """
        Define ship_recreate for process after shipping exception
        param order: sales order to which the order lines belong
        param line: sales order line records to procure
        param move_id: the ID of stock move
        param proc_id: the ID of procurement
        """
        move_obj = self.pool.get('stock.move')
        if order.state == 'shipping_except':
            for pick in order.picking_ids:
                for move in pick.move_lines:
                    if move.state == 'cancel':
                        mov_ids = move_obj.search(cr, uid, [('state', '=', 'cancel'),('sale_line_id', '=', line.id),('picking_id', '=', pick.id)])
                        if mov_ids:
                            for mov in move_obj.browse(cr, uid, mov_ids):
                                # FIXME: the following seems broken: what if move_id doesn't exist? What if there are several mov_ids? Shouldn't that be a sum?
                                move_obj.write(cr, uid, [move_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
                                self.pool.get('procurement.order').write(cr, uid, [proc_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
        return True

    def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
        start_date = self.date_to_datetime(cr, uid, start_date, context)
        date_planned = datetime.strptime(start_date, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=line.delay or 0.0)
        date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        return date_planned

    def _create_pickings_and_procurements(self, cr, uid, order, order_lines, picking_id=False, context=None):
        """Create the required procurements to supply sales order lines, also connecting
        the procurements to appropriate stock moves in order to bring the goods to the
        sales order's requested location.

        If ``picking_id`` is provided, the stock moves will be added to it, otherwise
        a standard outgoing picking will be created to wrap the stock moves, as returned
        by :meth:`~._prepare_order_picking`.

        Modules that wish to customize the procurements or partition the stock moves over
        multiple stock pickings may override this method and call ``super()`` with
        different subsets of ``order_lines`` and/or preset ``picking_id`` values.

        :param browse_record order: sales order to which the order lines belong
        :param list(browse_record) order_lines: sales order line records to procure
        :param int picking_id: optional ID of a stock picking to which the created stock moves
                               will be added. A new picking will be created if ommitted.
        :return: True
        """
        move_obj = self.pool.get('stock.move')
        picking_obj = self.pool.get('stock.picking')
        procurement_obj = self.pool.get('procurement.order')
        proc_ids = []

        for line in order_lines:
            if line.state == 'done':
                continue

            date_planned = self._get_date_planned(cr, uid, order, line, order.date_order, context=context)

            if line.product_id:
                if line.product_id.type in ('product', 'consu'):
                    if not picking_id:
                        picking_id = picking_obj.create(cr, uid, self._prepare_order_picking(cr, uid, order, context=context))
                    move_id = move_obj.create(cr, uid, self._prepare_order_line_move(cr, uid, order, line, picking_id, date_planned, context=context))
                else:
                    # a service has no stock move
                    move_id = False

                proc_id = procurement_obj.create(cr, uid, self._prepare_order_line_procurement(cr, uid, order, line, move_id, date_planned, context=context))
                proc_ids.append(proc_id)
                line.write({'procurement_id': proc_id})
                self.ship_recreate(cr, uid, order, line, move_id, proc_id)

        wf_service = netsvc.LocalService("workflow")
        if picking_id:
            wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
        for proc_id in proc_ids:
            wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)

        val = {}
        if order.state == 'shipping_except':
            val['state'] = 'progress'
            val['shipped'] = False

            if (order.order_policy == 'manual'):
                for line in order.order_line:
                    if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
                        val['state'] = 'manual'
                        break
        order.write(val)
        return True

    def action_ship_create(self, cr, uid, ids, context=None):
        for order in self.browse(cr, uid, ids, context=context):
            self._create_pickings_and_procurements(cr, uid, order, order.order_line, None, context=context)
        return True

    def action_ship_end(self, cr, uid, ids, context=None):
        for order in self.browse(cr, uid, ids, context=context):
            val = {'shipped': True}
            if order.state == 'shipping_except':
                val['state'] = 'progress'
                if (order.order_policy == 'manual'):
                    for line in order.order_line:
                        if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
                            val['state'] = 'manual'
                            break
            for line in order.order_line:
                towrite = []
                if line.state == 'exception':
                    towrite.append(line.id)
                if towrite:
                    self.pool.get('sale.order.line').write(cr, uid, towrite, {'state': 'done'}, context=context)
            res = self.write(cr, uid, [order.id], val)
        return True

    def has_stockable_products(self, cr, uid, ids, *args):
        for order in self.browse(cr, uid, ids):
            for order_line in order.order_line:
                if order_line.product_id and order_line.product_id.type in ('product', 'consu'):
                    return True
        return False