コード例 #1
0
ファイル: product.py プロジェクト: mbenyoub/server
class product_product(osv.osv):
    _inherit = "product.product"

    _columns = {
        'date_from': fields.dummy(string='Date From', type='date'),
        'date_to': fields.dummy(string='Date To', type='date'),
    }
コード例 #2
0
ファイル: product.py プロジェクト: eksotama/odoo-addons-1
class product_product(osv.osv):
    _inherit = "product.template"
    _columns = {
        'location_id':
        fields.dummy(string='Location',
                     relation='stock.location',
                     type='many2one'),
        'warehouse_id':
        fields.dummy(string='Warehouse',
                     relation='stock.warehouse',
                     type='many2one'),
    }
コード例 #3
0
class ProjectTask(osv.Model):
    _inherit = 'project.task'

    _columns = {
        'write_date': fields.datetime('Date Modified', readonly=True),
        'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True),
        'create_date': fields.datetime('Date Created', readonly=True),
        'create_uid': fields.many2one('res.users', 'Creator', readonly=True),
        'date_from_create': fields.dummy(string="Create Date From", type='date'),
        'date_to_create': fields.dummy(string="Create Date To", type='date'),
        'date_from_write': fields.dummy(string="Write Date From", type='date'),
        'date_to_write': fields.dummy(string="Write Date To", type='date'),
    }
コード例 #4
0
class twitter_config_settings(osv.osv_memory):
    _inherit = 'website.config.settings'

    _columns = {
        'twitter_api_key':
        fields.related(
            'website_id',
            'twitter_api_key',
            type="char",
            string='Twitter API Key',
            help=
            "Twitter API key you can get it from https://apps.twitter.com/app/new"
        ),
        'twitter_api_secret':
        fields.related(
            'website_id',
            'twitter_api_secret',
            type="char",
            string='Twitter API secret',
            help=
            "Twitter API secret you can get it from https://apps.twitter.com/app/new"
        ),
        'twitter_tutorial':
        fields.dummy(
            type="boolean",
            string="Show me how to obtain the Twitter API Key and Secret"),
        'twitter_screen_name':
        fields.related(
            'website_id',
            'twitter_screen_name',
            type="char",
            string='Get favorites from this screen name',
            help=
            "Screen Name of the Twitter Account from which you want to load favorites."
            "It does not have to match the API Key/Secret."),
    }

    def _check_twitter_authorization(self, cr, uid, config_id, context=None):
        website_obj = self.pool['website']
        website_config = self.browse(cr, uid, config_id, context=context)
        try:
            website_obj.fetch_favorite_tweets(cr,
                                              uid,
                                              [website_config.website_id.id],
                                              context=context)
        except Exception:
            _logger.warning('Failed to verify twitter API authorization',
                            exc_info=True)
            raise osv.except_osv(
                _('Twitter authorization error!'),
                _('Please double-check your Twitter API Key and Secret'))

    def create(self, cr, uid, vals, context=None):
        res_id = super(twitter_config_settings, self).create(cr,
                                                             uid,
                                                             vals,
                                                             context=context)
        if vals.get('twitter_api_key') and vals.get('twitter_api_secret'):
            self._check_twitter_authorization(cr, uid, res_id, context=context)
        return res_id
コード例 #5
0
class res_partner(osv.osv):

    _name = 'res.partner'
    _inherit = 'res.partner'

    _columns = {
        'lat': fields.float(u'Latitude', digits=(9, 6)),
        'lng': fields.float(u'Longitude', digits=(9, 6)),
        'map': fields.dummy(),
    }
コード例 #6
0
class ups_account_shipping(osv.osv):
    _name = "ups.account.shipping"
    _columns = {
        'name': fields.char('Name', size=64, required=True),
        'ups_account_id': fields.many2one('ups.account', 'UPS Account', required=True),
        'access_license': fields.related('ups_account_id', 'access_license', type='char', size=64, string='AccessLicenseNumber', required=True),
        'userid': fields.related('ups_account_id', 'userid', type='char', size=64, string='UserId', required=True),
        'password': fields.related('ups_account_id', 'password', type='char', size=64, string='Password', required=True),
        'ups_active': fields.related('ups_account_id', 'ups_active', string='Active', type='boolean'),
        'acc_no': fields.related('ups_account_id', 'acc_no', type='char', size=64, string='Account Number', required=True),
        'max_lim_size': fields.related('ups_account_id', 'max_lim_size', type='integer', required=True),
        'atten_name': fields.char('AttentionName', size=64, required=True, select=1),
        'tax_id_no': fields.char('Tax Identification Number', size=64 , select=1, help="Shipper's Tax Identification Number."),
        'logistic_company_id': fields.many2one('logistic.company', 'Parent Logistic Company'),
        'company_id': fields.dummy(string='Company ID', relation='res.company', type='many2one'), # For playing nice with the global domain.
#         'ups_shipping_service_ids': fields.one2many('ups.shipping.service.type', 'ups_account_id', 'Shipping Service'),
        'ups_shipping_service_ids':fields.many2many('ups.shipping.service.type', 'shipping_service_rel', 'ups_account_id', 'service_id', 'Shipping Service'),
        'address': fields.property(
           'res.partner',
           type='many2one',
           relation='res.partner',
           string="Shipper Address",
           view_load=True),
        'trademark': fields.char('Trademark', size=1024, select=1),
        'sandbox': fields.related('ups_account_id', 'sandbox', string='Sandbox mode', type='boolean'),
        'negotiated_rates': fields.boolean('Use Negotiated Rates')
    }
    _defaults = {
        'ups_active': True,
        'sandbox': False,
        'negotiated_rates': False
    }

    def onchange_ups_account(self, cr, uid, ids, ups_account_id=False, context=None):
        res = {
            'access_license': '',
            'userid': '',
            'password': '',
            'ups_active': True,
            'acc_no': ''
            }

        if ups_account_id:
            ups_account = self.pool.get('ups.account').browse(cr, uid, ups_account_id, context=context)
            res = {
                'access_license': ups_account.access_license,
                'userid': ups_account.userid,
                'password': ups_account.password,
                'ups_active': ups_account.ups_active,
                'acc_no': ups_account.acc_no
                }
        return {'value': res}
コード例 #7
0
class ProductProduct(orm.Model):
    '''
    inherited product.product to add customer field
    and amend search functions
    '''
    _inherit = 'product.product'

    _columns = {
        'customer_context_id':
        fields.dummy(string='Customer',
                     relation='res.partner',
                     type='many2one',
                     domain=[('customer', '=', True)]),
    }
コード例 #8
0
ファイル: twitter_config.py プロジェクト: vak0160/odoo-1
class twitter_config_settings(osv.TransientModel):
    _inherit = 'website.config.settings'

    _columns = {
        'twitter_api_key': fields.related(
            'website_id', 'twitter_api_key', type="char",
            string='Twitter API Key',
            help="Twitter API key you can get it from https://apps.twitter.com/app/new"),
        'twitter_api_secret': fields.related(
            'website_id', 'twitter_api_secret', type="char",
            string='Twitter API secret',
            help="Twitter API secret you can get it from https://apps.twitter.com/app/new"),
        'twitter_tutorial': fields.dummy(
            type="boolean", string="Show me how to obtain the Twitter API Key and Secret"),
        'twitter_screen_name': fields.related(
            'website_id', 'twitter_screen_name',
            type="char", string='Get favorites from this screen name',
            help="Screen Name of the Twitter Account from which you want to load favorites."
                 "It does not have to match the API Key/Secret."),
    }

    def _get_twitter_exception_message(self, error_code, context=None):
        TWITTER_EXCEPTION = {
            304: _('There was no new data to return.'),
            400: _('The request was invalid or cannot be otherwise served. Requests without authentication are considered invalid and will yield this response.'),
            401: _('Authentication credentials were missing or incorrect. Maybe screen name tweets are protected.'),
            403: _('The request is understood, but it has been refused or access is not allowed. Please check your Twitter API Key and Secret.'),
            429: _('Request cannot be served due to the applications rate limit having been exhausted for the resource.'),
            500: _('Twitter seems broken. Please retry later. You may consider posting an issue on Twitter forums to get help.'),
            502: _('Twitter is down or being upgraded.'),
            503: _('The Twitter servers are up, but overloaded with requests. Try again later.'),
            504: _('The Twitter servers are up, but the request could not be serviced due to some failure within our stack. Try again later.')
        }
        if error_code in TWITTER_EXCEPTION:
            return TWITTER_EXCEPTION[error_code]
        else:
            return _('HTTP Error: Something is misconfigured')

    def _check_twitter_authorization(self, cr, uid, config_id, context=None):
        website_obj = self.pool['website']
        website_config = self.browse(cr, uid, config_id, context=context)
        try:
            website_obj.fetch_favorite_tweets(cr, uid, [website_config.website_id.id], context=context)

        except HTTPError, e:
            _logger.info("%s - %s" % (e.code, e.reason), exc_info=True)
            raise UserError("%s - %s" % (e.code, e.reason) + ':' + self._get_twitter_exception_message(e.code, context))
        except URLError, e:
            _logger.info(_('We failed to reach a twitter server.'), exc_info=True)
            raise UserError(_('Internet connection refused') + ' ' + _('We failed to reach a twitter server.'))
コード例 #9
0
ファイル: fedex.py プロジェクト: sasakuma/shipping_api_fedex
class fedex_account_shipping(osv.osv):
    _name = "fedex.account.shipping"
    _columns = {
        'name': fields.char('Name', size=64, required=True),
        'fedex_account_id': fields.many2one('fedex.account', 'FedEx Account', required=True),
        'integrator_id': fields.related('fedex_account_id', 'fedex_integrator_id', type='char', size=64, string='IntegratorID', required=True),
        'password': fields.related('fedex_account_id', 'fedex_password', type='char', size=64, string='Password', required=True),
        'active': fields.boolean('Active'),
        'key': fields.related('fedex_account_id', 'fedex_key', type='char', size=64, string='Key', required=True),
        'account_number': fields.related('fedex_account_id', 'fedex_account_number', type='char', size=64, string='Account Number', required=True),
        'meter_number': fields.related('fedex_account_id', 'fedex_meter_number', type='char', size=64, string='Meter Number', required=True),
        'tax_id_no': fields.char('Tax Identification Number', size=64 , select=1, help="Shipper's Tax Identification Number."),
        'logistic_company_id': fields.many2one('logistic.company', 'Parent Logistic Company'),
        'company_id': fields.dummy(string='Company ID', relation='res.company', type='many2one'), # For playing nice with the global domain.
        'address': fields.property(
           'res.partner',
           type='many2one',
           relation='res.partner',
           string="Shipper Address",
           view_load=True),
        'sandbox': fields.boolean('Sandbox mode')
    }
    _defaults = {
        'active': True,
        'sandbox': False
    }

    def onchange_fedex_account(self, cr, uid, ids, fedex_account_id=False, context=None):
        res = {
            'key': '',
            'integrator_id': '',
            'password': '',
            'account_number': '',
            'meter_number': '',
            'sandbox': True
        }

        if fedex_account_id:
            fedex_account = self.pool.get('fedex.account').browse(cr, uid, fedex_account_id, context=context)
            res = {
                'key': fedex_account.fedex_key,
                'integrator_id': fedex_account.fedex_integrator_id,
                'password': fedex_account.fedex_password,
                'account_number': fedex_account.fedex_account_number,
                'meter_number': fedex_account.fedex_meter_number,
                'sandbox': fedex_account.test_mode
            }
        return {'value': res}
コード例 #10
0
ファイル: res_config.py プロジェクト: zaoral/odoo
class AccountPaymentConfig(osv.TransientModel):
    _inherit = 'account.config.settings'

    _columns = {
        'module_payment_paypal': fields.boolean(
            'Paypal',
            help='-It installs the module payment_paypal.'),
        'module_payment_ogone': fields.boolean(
            'Ogone',
            help='-It installs the module payment_ogone.'),
        'module_payment_adyen': fields.boolean(
            'Adyen',
            help='-It installs the module payment_adyen.'),
        'module_payment_buckaroo': fields.boolean(
            'Buckaroo',
            help='-It installs the module payment_buckaroo.'),
        'module_payment_authorize': fields.dummy(
            'Authorize.Net',
            help='-It installs the module payment_authorize.'),
    }
コード例 #11
0
ファイル: fleet_old.py プロジェクト: sm2x/foi_parcurs
class fleet_map_sheet(models.Model):
    _name = 'fleet.map.sheet'
    _description = 'Fleet Map Sheet'

    def _get_odometer(self, cr, uid, ids, field_name, arg, context):
        res = dict.fromkeys(ids, 0)
        for record in self.browse(cr, uid, ids, context=context):
            if field_name == 'odometer_start':
                if record.odometer_start_id.id:
                    res[record.id] = record.odometer_start_id.value
                else:
                    ids = self.pool.get('fleet.vehicle.odometer').search(
                        cr,
                        uid, [('vehicle_id', '=', record.vehicle_id.id),
                              ('date', '<=', record.date_start)],
                        limit=1,
                        order='date desc')
                    if len(ids) > 0:
                        res[record.id] = self.pool.get(
                            'fleet.vehicle.odometer').browse(
                                cr, uid, ids[0], context=context).value
                    else:  # chiar sa nu fie nici unul?
                        if record.odometer_end_id.id:
                            res[record.
                                id] = record.odometer_end_id.value - record.distance_total
            if field_name == 'odometer_end':
                if record.odometer_end_id.id:
                    res[record.id] = record.odometer_end_id.value
                else:
                    ids = self.pool.get('fleet.vehicle.odometer').search(
                        cr,
                        uid, [('vehicle_id', '=', record.vehicle_id.id),
                              ('date', '>=', record.date_end)],
                        limit=1,
                        order='date')
                    if len(ids) > 0:
                        res[record.id] = self.pool.get(
                            'fleet.vehicle.odometer').browse(
                                cr, uid, ids[0], context=context).value
                    else:
                        res[record.
                            id] = record.odometer_start + record.distance_total
        return res

    def _set_odometer(self,
                      cr,
                      uid,
                      id,
                      field_name,
                      value,
                      args=None,
                      context=None):
        if value:
            for record in self.browse(cr, uid, [id], context=context):
                if field_name == 'odometer_start':
                    data = {
                        'value': value,
                        'date': record.date_start,
                        'vehicle_id': record.vehicle_id.id
                    }
                    if record.odometer_start_id.id:
                        self.pool.get('fleet.vehicle.odometer').write(
                            cr,
                            uid, [record.odometer_start_id.id],
                            data,
                            context=context)
                    else:
                        res_id = record.odometer_start_id = self.pool.get(
                            'fleet.vehicle.odometer').create(cr,
                                                             uid,
                                                             data,
                                                             context=context)
                        self.write(cr,
                                   uid, [id], {'odometer_start_id': res_id},
                                   context=context)

                if field_name == 'odometer_end':
                    data = {
                        'value': value,
                        'date': record.date_end,
                        'vehicle_id': record.vehicle_id.id
                    }
                    if record.odometer_end_id.id:
                        self.pool.get('fleet.vehicle.odometer').write(
                            cr,
                            uid, [record.odometer_end_id.id],
                            data,
                            context=context)
                    else:
                        res_id = record.odometer_end_id = self.pool.get(
                            'fleet.vehicle.odometer').create(cr,
                                                             uid,
                                                             data,
                                                             context=context)
                        self.write(cr,
                                   uid, [id], {'odometer_end_id': res_id},
                                   context=context)
        return

    def _amount_all(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        for map_sheet in self.browse(cr, uid, ids, context=context):
            res[map_sheet.id] = {
                'liter_total': 0.0,
                'amount_total': 0.0,
                'distance_total': 0.0,
                'norm_cons': 0.0,
                'odometer_end': 0.0,
            }
            liter = amount = 0.0
            distance_total = 0.0
            norm_cons = 0.0
            for log_fuel in map_sheet.log_fuel_ids:
                liter += log_fuel.liter
                amount += log_fuel.amount
            res[map_sheet.id]['liter_total'] = liter
            res[map_sheet.id]['amount_total'] = amount

            for route in map_sheet.route_log_ids:
                distance_total += route.distance
                norm_cons += route.norm_cons
            res[map_sheet.id]['distance_total'] = distance_total
            res[map_sheet.id][
                'norm_cons'] = norm_cons  #distance_total * map_sheet.vehicle_id.avg_cons / 100
            res[map_sheet.
                id]['odometer_end'] = map_sheet.odometer_start + distance_total
#            self._set_odometer(cr, uid, [map_sheet.id],'odometer_end',map_sheet.odometer_start + distance_total,context=context)

        return res

    def _get_map_sheet_fuel(self, cr, uid, ids, context=None):
        result = {}
        for line in self.pool.get('fleet.vehicle.log.fuel').browse(
                cr, uid, ids, context=context):
            result[line.map_sheet_id.id] = True
        return result.keys()

    def _get_map_sheet_route(self, cr, uid, ids, context=None):
        result = {}
        for line in self.pool.get('fleet.route.log').browse(cr,
                                                            uid,
                                                            ids,
                                                            context=context):
            result[line.map_sheet_id.id] = True
        return result.keys()

    def _get_reservoir_level_start(self,
                                   cr,
                                   uid,
                                   ids,
                                   prop,
                                   unknow_none,
                                   context=None):
        res = {}
        for record in self.browse(cr, uid, ids, context=context):
            level_obj = self.pool.get('fleet.reservoir.level')
            res[record.id] = level_obj.get_level_to(cr, uid,
                                                    record.vehicle_id.id,
                                                    record.date_start)
        return res

    def _get_reservoir_level_end(self,
                                 cr,
                                 uid,
                                 ids,
                                 prop,
                                 unknow_none,
                                 context=None):
        res = {}
        for record in self.browse(cr, uid, ids, context=context):
            level_obj = self.pool.get('fleet.reservoir.level')
            res[record.id] = level_obj.get_level_to(cr, uid,
                                                    record.vehicle_id.id,
                                                    record.date_end)
        return res

    _columns = {
        'name':
        fields.char('Number',
                    size=20,
                    required=True,
                    readonly=True,
                    states={'draft': [('readonly', False)]}),
        'date':
        fields.date('Date',
                    required=True,
                    readonly=True,
                    states={'draft': [('readonly', False)]}),
        'vehicle_id':
        fields.many2one('fleet.vehicle',
                        'Vehicle',
                        required=True,
                        help='Vehicle',
                        readonly=True,
                        states={'draft': [('readonly', False)]}),
        'category_id':
        fields.related('vehicle_id',
                       'category_id',
                       type="many2one",
                       readonly=True,
                       relation='fleet.vehicle.category',
                       string="Vehicle Category"),
        'driver_id':
        fields.many2one('res.partner',
                        'Driver',
                        help='Driver of the vehicle',
                        states={'done': [('readonly', True)]}),
        'driver2_id':
        fields.many2one('res.partner',
                        'Backup Driver',
                        help='Backup driver of the vehicle',
                        states={'done': [('readonly', True)]}),
        'avg_cons':
        fields.related('vehicle_id',
                       'avg_cons',
                       type="float",
                       readonly=True,
                       string="Average Consumption"),
        'odometer_start_id':
        fields.many2one('fleet.vehicle.odometer',
                        string='ID Odometer start',
                        domain="[('vehicle_id','=',vehicle_id)]",
                        states={'done': [('readonly', True)]}),
        'odometer_end_id':
        fields.many2one('fleet.vehicle.odometer',
                        string='ID Odometer end',
                        domain="[('vehicle_id','=',vehicle_id)]",
                        states={'done': [('readonly', True)]}),
        'date_start':
        fields.datetime('Date Start',
                        help='Date time at the start of this map sheet',
                        states={'done': [('readonly', True)]}),
        'date_start_old':
        fields.dummy('Date Start', type='datetime'),
        'date_end':
        fields.datetime('Date End',
                        help='Date time at the end of this map sheet',
                        states={'done': [('readonly', True)]}),
        'odometer_start':
        fields.function(
            _get_odometer,
            fnct_inv=_set_odometer,
            type='float',
            string=_('Odometer Start'),
            help=
            'Odometer measure of the vehicle at the start of this map sheet',
            states={'done': [('readonly', True)]}),
        'odometer_end':
        fields.function(
            _get_odometer,
            fnct_inv=_set_odometer,
            type='float',
            string=_('Odometer End'),
            help='Odometer measure of the vehicle at the end of this map sheet',
            states={'done': [('readonly', True)]}),
        'state':
        fields.selection(
            [('draft', 'Draft'), ('open', 'In Progress'), ('done', 'Done'),
             ('cancel', 'Cancelled')],
            string='Status',
            readonly=True,
            help="When the Map Sheet is created the status is set to 'Draft'.\n\
                  When the Map Sheet is in progress the status is set to 'In Progress' .\n\
                  When the Map Sheet is closed, the status is set to 'Done'."),
        'log_fuel_ids':
        fields.one2many('fleet.vehicle.log.fuel',
                        'map_sheet_id',
                        'Fuel log',
                        states={'done': [('readonly', True)]}),
        'route_log_ids':
        fields.one2many('fleet.route.log',
                        'map_sheet_id',
                        'Route Logs',
                        states={'done': [('readonly', True)]}),
        'liter_total':
        fields.function(_amount_all,
                        type='float',
                        string='Total Liter',
                        store={
                            'fleet.vehicle.log.fuel':
                            (_get_map_sheet_fuel, None, 10),
                            'fleet.route.log':
                            (_get_map_sheet_route, None, 10),
                        },
                        multi="sums",
                        help="The total liters"),
        'amount_total':
        fields.function(_amount_all,
                        type='float',
                        string='Total Amount',
                        store={
                            'fleet.vehicle.log.fuel':
                            (_get_map_sheet_fuel, None, 10),
                            'fleet.route.log':
                            (_get_map_sheet_route, None, 10),
                        },
                        multi="sums",
                        help="The total amount for fuel"),
        'distance_total':
        fields.function(_amount_all,
                        type='float',
                        string='Total distance',
                        store={
                            'fleet.vehicle.log.fuel':
                            (_get_map_sheet_fuel, None, 10),
                            'fleet.route.log':
                            (_get_map_sheet_route, None, 10),
                        },
                        multi="odmeter",
                        help="The total distance"),
        'norm_cons':
        fields.function(_amount_all,
                        type='float',
                        string='Normal Consumption',
                        store={
                            'fleet.vehicle.log.fuel':
                            (_get_map_sheet_fuel, None, 10),
                            'fleet.route.log':
                            (_get_map_sheet_route, None, 10),
                        },
                        multi="odmeter",
                        help="The Normal Consumption"),
        'company_id':
        fields.many2one('res.company',
                        'Company',
                        required=True,
                        states={'done': [('readonly', True)]}),
        'reservoir_level_start':
        fields.function(
            _get_reservoir_level_start,
            type="float",
            string='Level Reservoir Start',
            store=False,
            help="Fuel level in the reservoir at the beginning of road map"),
        'reservoir_level_end':
        fields.function(
            _get_reservoir_level_end,
            type="float",
            string='Level Reservoir End',
            store=False,
            help="Fuel level in the reservoir at the beginning of road map"),
    }

    def _conv_local_datetime_to_utc(self, cr, uid, date, context):
        tz_name = context['tz']
        local = pytz.timezone(tz_name)
        naive = datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
        local_dt = local.localize(naive, is_dst=None)
        utc_dt = local_dt.astimezone(pytz.utc)
        return utc_dt.strftime('%Y-%m-%d %H:%M:%S')

    def _get_default_date_start(self, cr, uid, context):
        if context and 'date' in context:
            res = self._conv_local_datetime_to_utc(
                cr, uid, context['date'][:10] + ' 00:00:00', context)
        else:
            res = time.strftime('%Y-%m-%d %H:%M:%S')
        return res

    def _get_default_date_end(self, cr, uid, context):
        if context and 'date' in context:
            res = self._conv_local_datetime_to_utc(
                cr, uid, context['date'][:10] + ' 23:59:59', context)
        else:
            res = time.strftime('%Y-%m-%d %H:%M:%S')
        return res

    _defaults = {
        'state':
        'draft',
        'date':
        lambda self, cr, uid, context: context['date']
        if context and 'date' in context else time.strftime('%Y-%m-%d'),
        'date_start':
        _get_default_date_start,
        'date_end':
        _get_default_date_end,
        'name':
        lambda x, y, z, c: x.pool.get('ir.sequence').next_by_code(
            y, z, 'fleet.map.sheet') or '/',
        'company_id':
        lambda self, cr, uid, c: self.pool.get('res.company').
        _company_default_get(cr, uid, 'mrp.production', context=c),
        'vehicle_id':
        lambda self, cr, uid, context: context['vehicle_id']
        if context and 'vehicle_id' in context else None
    }

    def copy(self, cr, uid, id, default=None, context=None):
        if not default:
            default = {}

        record = self.browse(cr, uid, id, context=context)

        date_start = datetime.strptime(record.date_start,
                                       tools.DEFAULT_SERVER_DATETIME_FORMAT)
        date_start = date_start + timedelta(days=1)
        date_start = datetime.strftime(date_start,
                                       tools.DEFAULT_SERVER_DATETIME_FORMAT)

        date_end = datetime.strptime(record.date_start,
                                     tools.DEFAULT_SERVER_DATETIME_FORMAT)
        date_end = date_end + timedelta(days=1)
        date_end = datetime.strftime(date_end,
                                     tools.DEFAULT_SERVER_DATETIME_FORMAT)

        date = datetime.strptime(record.date, tools.DEFAULT_SERVER_DATE_FORMAT)
        date = date + timedelta(days=1)
        date = datetime.strftime(date, tools.DEFAULT_SERVER_DATE_FORMAT)
        #TODO: de introdus pozitii si pentru rute cu data incrementata
        default.update({
            'log_fuel_ids': [],
            'name':
            self.pool.get('ir.sequence').next_by_code(cr, uid,
                                                      'fleet.map.sheet'),
            'date':
            date,
            'date_start':
            date_start,
            'date_start':
            date_end,
        })
        new_id = super(fleet_map_sheet, self).copy(cr,
                                                   uid,
                                                   id,
                                                   default,
                                                   context=context)
        return new_id

    def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
        if not vehicle_id:
            return {}
        vehicle = self.pool.get('fleet.vehicle').browse(cr,
                                                        uid,
                                                        vehicle_id,
                                                        context=context)
        return {
            'value': {
                'driver_id': vehicle.driver_id.id,
                'driver2_id': vehicle.driver2_id.id,
            }
        }

    def on_change_date_start(self,
                             cr,
                             uid,
                             ids,
                             date_start,
                             date_end,
                             date_start_old,
                             route_log_ids,
                             context=None):
        # se determina diferenta din dintre data veche si noua data !!
        if len(ids) != 1:
            return {}

        if not date_start_old:
            date_start_old = self.read(cr,
                                       uid,
                                       ids, ['date_start'],
                                       context=context)[0]['date_start']

        # map_sheet = self.browse(cr, uid, ids, context=context)[0]
        new_date_start_int = str_to_datetime(date_start)
        old_date_start_int = str_to_datetime(date_start_old)

        date_dif = new_date_start_int - old_date_start_int

        new_date_end_int = str_to_datetime(date_end)
        date_end = datetime_to_str(new_date_end_int + date_dif)

        route_log_list = self.resolve_2many_commands(
            cr,
            uid,
            'route_log_ids',
            route_log_ids, ['id', 'date_begin', 'date_end'],
            context=context)

        if len(route_log_ids) > 0:
            for i in range(len(route_log_ids)):
                routes = [
                    x for x in route_log_list if x['id'] == route_log_ids[i][1]
                ]
                if routes:
                    route = routes[0]
                    date_begin_int = str_to_datetime(route['date_begin'])
                    date_end_int = str_to_datetime(route['date_end'])
                    route_log_ids[i][2] = {
                        'date_begin':
                        datetime_to_str(date_begin_int + date_dif),
                        'date_end': datetime_to_str(date_end_int + date_dif)
                    }
                    route_log_ids[i][0] = 1

        return {
            'value': {
                'date_end': date_end,
                'date_start_old': date_start,
                'route_log_ids': route_log_ids
            }
        }

    def on_change_route_log(self,
                            cr,
                            uid,
                            ids,
                            route_log_ids,
                            date_start,
                            date_end,
                            context=None):
        return {}
        if not route_log_ids:
            return {}

        new_date_start = date_start
        new_date_end = date_end

        for route_log in route_log_ids:
            values = route_log[2]
            if values and 'date_end' in values and values[
                    'date_end'] > new_date_end:
                new_date_end = values['date_end']

            if values and 'date_begin' in values and values[
                    'date_begin'] < new_date_start:
                new_date_start = values['date_begin']

        return {
            'value': {
                #   'date_start':new_date_start,
                'date_end': new_date_end,
            }
        }

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

        for map_sheet in self.browse(cr, uid, ids, context=context):
            for fuel_log in map_sheet.log_fuel_ids:
                self.pool.get('fleet.vehicle.log.fuel').write(
                    cr,
                    uid,
                    fuel_log.id, {'vehicle_id': map_sheet.vehicle_id.id},
                    context=context)

            for route_log in map_sheet.route_log_ids:
                self.pool.get('fleet.route.log').write(
                    cr,
                    uid,
                    route_log.id, {'vehicle_id': map_sheet.vehicle_id.id},
                    context=context)
            if map_sheet.odometer_start_id:
                self.pool.get('fleet.vehicle.odometer').write(
                    cr,
                    uid,
                    map_sheet.odometer_start_id.id,
                    {'vehicle_id': map_sheet.vehicle_id.id},
                    context=context)
            if map_sheet.odometer_end_id:
                self.pool.get('fleet.vehicle.odometer').write(
                    cr,
                    uid,
                    map_sheet.odometer_end_id.id,
                    {'vehicle_id': map_sheet.vehicle_id.id},
                    context=context)
        res = super(fleet_map_sheet, self).write(cr,
                                                 uid,
                                                 ids,
                                                 vals,
                                                 context=context)
        return res

    def unlink(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        """Allows to delete map sheet in draft,cancel states"""
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.state not in ['draft', 'cancel']:
                raise osv.except_osv(
                    _('Invalid Action!'),
                    _('Cannot delete a map sheet which is in state \'%s\'.') %
                    (rec.state, ))
        return super(fleet_map_sheet, self).unlink(cr,
                                                   uid,
                                                   ids,
                                                   context=context)

    def button_dummy(self, cr, uid, ids, context=None):
        return True

    def action_get_log_fuel(self, cr, uid, ids, context=None):
        for record in self.browse(cr, uid, ids, context=context):
            fuel_log_ids = self.pool.get('fleet.vehicle.log.fuel').search(
                cr, uid, [('vehicle_id', '=', record.vehicle_id.id),
                          ('date_time', '>=', record.date_start),
                          ('date_time', '<=', record.date_end),
                          ('map_sheet_id', '=', None)])
            if len(fuel_log_ids) > 0:
                self.pool.get('fleet.vehicle.log.fuel').write(
                    cr, uid, fuel_log_ids, {'map_sheet_id': record.id},
                    context)
        return True

    def action_get_route_log(self, cr, uid, ids, context=None):
        for record in self.browse(cr, uid, ids, context=context):
            log_route_ids = self.pool.get('fleet.route.log').search(
                cr, uid, [('vehicle_id', '=', record.vehicle_id.id),
                          ('date_begin', '>=', record.date_start[:10]),
                          ('date_end', '<=', record.date_end),
                          ('map_sheet_id', '=', None)])
            if len(log_route_ids) > 0:
                self.pool.get('fleet.route.log').write(
                    cr, uid, log_route_ids, {'map_sheet_id': record.id},
                    context)
        return True

    def action_open(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state': 'open'})
        return True

    def action_done(self, cr, uid, ids, context=None):
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.distance_total == 0:
                raise osv.except_osv(
                    _('Invalid Action!'),
                    _('Cannot set done a map sheet which distance equal with zero.'
                      ))

        self.write(cr, uid, ids, {'state': 'done'})
        for map_sheet in self.browse(cr, uid, ids, context=context):
            for fuel_log in map_sheet.log_fuel_ids:
                self.pool.get('fleet.vehicle.log.fuel').write(
                    cr, uid, fuel_log.id, {'state': 'done'}, context=context)
        return True


# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
コード例 #12
0
class product_template(osv.osv):
    _name = 'product.template'
    _inherit = 'product.template'

    def _product_available(self, cr, uid, ids, name, arg, context=None):
        prod_available = {}
        product_ids = self.browse(cr, uid, ids, context=context)
        var_ids = []
        for product in product_ids:
            var_ids += [p.id for p in product.product_variant_ids]
        variant_available = self.pool['product.product']._product_available(
            cr, uid, var_ids, context=context)

        for product in product_ids:
            qty_available = 0
            virtual_available = 0
            incoming_qty = 0
            outgoing_qty = 0
            for p in product.product_variant_ids:
                qty_available += variant_available[p.id]["qty_available"]
                virtual_available += variant_available[
                    p.id]["virtual_available"]
                incoming_qty += variant_available[p.id]["incoming_qty"]
                outgoing_qty += variant_available[p.id]["outgoing_qty"]
            prod_available[product.id] = {
                "qty_available": qty_available,
                "virtual_available": virtual_available,
                "incoming_qty": incoming_qty,
                "outgoing_qty": outgoing_qty,
            }
        return prod_available

    def _search_product_quantity(self, cr, uid, obj, name, domain, context):
        prod = self.pool.get("product.product")
        product_variant_ids = prod.search(cr, uid, domain, context=context)
        return [('product_variant_ids', 'in', product_variant_ids)]

    def _product_available_text(self,
                                cr,
                                uid,
                                ids,
                                field_names=None,
                                arg=False,
                                context=None):
        res = {}
        for product in self.browse(cr, uid, ids, context=context):
            res[product.id] = str(product.qty_available) + _(" On Hand")
        return res

    def _compute_nbr_reordering_rules(self,
                                      cr,
                                      uid,
                                      ids,
                                      field_names=None,
                                      arg=None,
                                      context=None):
        res = {
            id: {
                'nbr_reordering_rules': 0,
                'reordering_min_qty': 0,
                'reordering_max_qty': 0
            }
            for id in ids
        }
        product_data = self.pool['stock.warehouse.orderpoint'].read_group(
            cr,
            uid, [('product_id.product_tmpl_id', 'in', ids)],
            ['product_id', 'product_min_qty', 'product_max_qty'],
            ['product_id'],
            context=context)
        for data in product_data:
            product_tmpl_id = data['__domain'][1][2][0]
            res[product_tmpl_id][
                'nbr_reordering_rules'] = res[product_tmpl_id].get(
                    'nbr_reordering_rules', 0) + int(data['product_id_count'])
            res[product_tmpl_id]['reordering_min_qty'] = data[
                'product_min_qty']
            res[product_tmpl_id]['reordering_max_qty'] = data[
                'product_max_qty']
        return res

    def _get_product_template_type(self, cr, uid, context=None):
        res = super(product_template,
                    self)._get_product_template_type(cr, uid, context=context)
        if 'product' not in [item[0] for item in res]:
            res.append(('product', _('Stockable Product')))
        return res

    _columns = {
        'property_stock_procurement':
        fields.property(
            type='many2one',
            relation='stock.location',
            string="Procurement Location",
            domain=[('usage', 'like', 'procurement')],
            help=
            "This stock location will be used, instead of the default one, as the source location for stock moves generated by procurements."
        ),
        'property_stock_production':
        fields.property(
            type='many2one',
            relation='stock.location',
            string="Production Location",
            domain=[('usage', 'like', 'production')],
            help=
            "This stock location will be used, instead of the default one, as the source location for stock moves generated by manufacturing orders."
        ),
        'property_stock_inventory':
        fields.property(
            type='many2one',
            relation='stock.location',
            string="Inventory Location",
            domain=[('usage', 'like', 'inventory')],
            help=
            "This stock location will be used, instead of the default one, as the source location for stock moves generated when you do an inventory."
        ),
        'sale_delay':
        fields.float(
            'Customer Lead Time',
            help=
            "The average delay in days between the confirmation of the customer order and the delivery of the finished products. It's the time you promise to your customers."
        ),
        'tracking':
        fields.selection(selection=[('serial', 'By Unique Serial Number'),
                                    ('lot', 'By Lots'),
                                    ('none', 'No Tracking')],
                         string="Tracking",
                         required=True),
        'description_picking':
        fields.text('Description on Picking', translate=True),
        # sum of product variant qty
        # 'reception_count': fields.function(_product_available, multi='qty_available',
        #     fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'),
        # 'delivery_count': fields.function(_product_available, multi='qty_available',
        #     fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'),
        'qty_available':
        fields.function(
            _product_available,
            multi='qty_available',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            fnct_search=_search_product_quantity,
            type='float',
            string='Quantity On Hand'),
        'virtual_available':
        fields.function(
            _product_available,
            multi='qty_available',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            fnct_search=_search_product_quantity,
            type='float',
            string='Forecasted Quantity'),
        'incoming_qty':
        fields.function(
            _product_available,
            multi='qty_available',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            fnct_search=_search_product_quantity,
            type='float',
            string='Incoming'),
        'outgoing_qty':
        fields.function(
            _product_available,
            multi='qty_available',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            fnct_search=_search_product_quantity,
            type='float',
            string='Outgoing'),
        'location_id':
        fields.dummy(string='Location',
                     relation='stock.location',
                     type='many2one'),
        'warehouse_id':
        fields.dummy(string='Warehouse',
                     relation='stock.warehouse',
                     type='many2one'),
        'route_ids':
        fields.many2many(
            'stock.location.route',
            'stock_route_product',
            'product_id',
            'route_id',
            'Routes',
            domain="[('product_selectable', '=', True)]",
            help=
            "Depending on the modules installed, this will allow you to define the route of the product: whether it will be bought, manufactured, MTO/MTS,..."
        ),
        'nbr_reordering_rules':
        fields.function(_compute_nbr_reordering_rules,
                        string='Reordering Rules',
                        type='integer',
                        multi=True),
        'reordering_min_qty':
        fields.function(_compute_nbr_reordering_rules,
                        type='float',
                        multi=True),
        'reordering_max_qty':
        fields.function(_compute_nbr_reordering_rules,
                        type='float',
                        multi=True),
        'route_from_categ_ids':
        fields.related('categ_id',
                       'total_route_ids',
                       type="many2many",
                       relation="stock.location.route",
                       string="Category Routes"),
    }

    _defaults = {
        'sale_delay': 7,
        'tracking': 'none',
    }

    def action_view_routes(self, cr, uid, ids, context=None):
        route_obj = self.pool.get("stock.location.route")
        act_obj = self.pool.get('ir.actions.act_window')
        mod_obj = self.pool.get('ir.model.data')
        product_route_ids = set()
        for product in self.browse(cr, uid, ids, context=context):
            product_route_ids |= set([r.id for r in product.route_ids])
            product_route_ids |= set(
                [r.id for r in product.categ_id.total_route_ids])
        route_ids = route_obj.search(cr,
                                     uid, [
                                         '|',
                                         ('id', 'in', list(product_route_ids)),
                                         ('warehouse_selectable', '=', True)
                                     ],
                                     context=context)
        result = mod_obj.xmlid_to_res_id(cr,
                                         uid,
                                         'stock.action_routes_form',
                                         raise_if_not_found=True)
        result = act_obj.read(cr, uid, [result], context=context)[0]
        result['domain'] = "[('id','in',[" + ','.join(map(str,
                                                          route_ids)) + "])]"
        return result

    def onchange_tracking(self, cr, uid, ids, tracking, context=None):
        if not tracking:
            return {}
        product_product = self.pool['product.product']
        variant_ids = product_product.search(cr,
                                             uid,
                                             [('product_tmpl_id', 'in', ids)],
                                             context=context)
        return product_product.onchange_tracking(cr,
                                                 uid,
                                                 variant_ids,
                                                 tracking,
                                                 context=context)

    def _get_products(self, cr, uid, ids, context=None):
        products = []
        for prodtmpl in self.browse(cr, uid, ids, context=None):
            products += [x.id for x in prodtmpl.product_variant_ids]
        return products

    def _get_act_window_dict(self, cr, uid, name, context=None):
        mod_obj = self.pool.get('ir.model.data')
        act_obj = self.pool.get('ir.actions.act_window')
        result = mod_obj.xmlid_to_res_id(cr,
                                         uid,
                                         name,
                                         raise_if_not_found=True)
        result = act_obj.read(cr, uid, [result], context=context)[0]
        return result

    def action_open_quants(self, cr, uid, ids, context=None):
        products = self._get_products(cr, uid, ids, context=context)
        result = self._get_act_window_dict(cr,
                                           uid,
                                           'stock.product_open_quants',
                                           context=context)
        result['domain'] = "[('product_id','in',[" + ','.join(
            map(str, products)) + "])]"
        result[
            'context'] = "{'search_default_locationgroup': 1, 'search_default_internal_loc': 1}"
        return result

    def action_view_orderpoints(self, cr, uid, ids, context=None):
        products = self._get_products(cr, uid, ids, context=context)
        result = self._get_act_window_dict(cr,
                                           uid,
                                           'stock.product_open_orderpoint',
                                           context=context)
        if len(ids) == 1 and len(products) == 1:
            result['context'] = "{'default_product_id': " + str(
                products[0]) + ", 'search_default_product_id': " + str(
                    products[0]) + "}"
        else:
            result['domain'] = "[('product_id','in',[" + ','.join(
                map(str, products)) + "])]"
            result['context'] = "{}"
        return result

    def action_view_stock_moves(self, cr, uid, ids, context=None):
        products = self._get_products(cr, uid, ids, context=context)
        result = self._get_act_window_dict(cr,
                                           uid,
                                           'stock.act_product_stock_move_open',
                                           context=context)
        if products:
            result['context'] = "{'default_product_id': %d}" % products[0]
        result['domain'] = "[('product_id.product_tmpl_id','in',[" + ','.join(
            map(str, ids)) + "])]"
        return result

    def write(self, cr, uid, ids, vals, context=None):
        if 'uom_id' in vals:
            new_uom = self.pool.get('product.uom').browse(cr,
                                                          uid,
                                                          vals['uom_id'],
                                                          context=context)
            for product in self.browse(cr, uid, ids, context=context):
                old_uom = product.uom_id
                if old_uom != new_uom:
                    if self.pool.get('stock.move').search(
                            cr,
                            uid,
                        [('product_id', 'in',
                          [x.id for x in product.product_variant_ids]),
                         ('state', '=', 'done')],
                            limit=1,
                            context=context):
                        raise UserError(
                            _("You can not change the unit of measure of a product that has already been used in a done stock move. If you need to change the unit of measure, you may deactivate this product."
                              ))
        return super(product_template, self).write(cr,
                                                   uid,
                                                   ids,
                                                   vals,
                                                   context=context)
コード例 #13
0
class product_product(orm.Model):

    _inherit = 'product.product'

    def _get_all_pricelist_ids(self, cr, uid, ids, field_name, arg, context):
        context = context or self.pool['res.users'].context_get(cr, uid)
        ret = {}
        if context.get('show_listprice', False):
            partner_name = context.get('partner_name', False)
            if partner_name:
                partner_obj = self.pool['res.partner']
                partner_ids = partner_obj.search(cr,
                                                 uid,
                                                 [('name', '=', partner_name)],
                                                 context=context)
                pricelist_customer_version_ids = []
                pricelist_version_ids = []
                if partner_ids:
                    partner = partner_obj.browse(cr,
                                                 uid,
                                                 partner_ids[0],
                                                 context=context)
                    product_pricelist_id = partner.property_product_pricelist and partner.property_product_pricelist.id or False
                    pricelist_customer_version_ids = self.pool[
                        'product.pricelist.version'].search(
                            cr,
                            uid, [('pricelist_id', '=', product_pricelist_id)],
                            context=context)
                    cr.execute(
                        " SELECT sale_shop.pricelist_id FROM sale_shop GROUP BY pricelist_id;"
                    )
                    pricelist_version_ids = self.pool[
                        'product.pricelist.version'].search(
                            cr,
                            uid, [('pricelist_id', 'in', [
                                pricelist_version_id[0]
                                for pricelist_version_id in cr.fetchall()
                            ])],
                            context=context)
            else:
                cr.execute(
                    " SELECT product_pricelist_version.id " \
                    " FROM " \
                    "  product_pricelist, " \
                    "  product_pricelist_version, " \
                    "  res_partner " \
                    " WHERE " \
                    "  product_pricelist.partner_id = res_partner.id AND " \
                    "  product_pricelist_version.pricelist_id = product_pricelist.id AND " \
                    "  product_pricelist.type = 'sale' AND " \
                    "  product_pricelist.partner_id IS NOT NULL  AND " \
                    "  product_pricelist.active IS TRUE AND " \
                    "  product_pricelist_version.active IS TRUE " \
                    " ORDER BY" \
                    "  res_partner.name ASC;"
                )
                pricelist_customer_version_ids = [
                    pricelist_version_id[0]
                    for pricelist_version_id in cr.fetchall()
                ]

                cr.execute(
                    " SELECT product_pricelist_version.id " \
                    " FROM " \
                    "  product_pricelist, " \
                    "  product_pricelist_version " \
                    " WHERE " \
                    "  product_pricelist_version.pricelist_id = product_pricelist.id AND " \
                    "  product_pricelist.type = 'sale' AND " \
                    "  product_pricelist.partner_id IS NULL  AND " \
                    "  product_pricelist.active IS TRUE AND " \
                    "  product_pricelist_version.active IS TRUE " \
                    " ORDER BY" \
                    "  product_pricelist.name ASC;"
                )
                pricelist_version_ids = [
                    pricelist_version_id[0]
                    for pricelist_version_id in cr.fetchall()
                ]

            for product_id in ids:
                ret[product_id] = {
                    'partner_pricelist_ids': pricelist_customer_version_ids,
                    'generic_pricelist_ids': pricelist_version_ids
                }
        else:
            for product_id in ids:
                ret[product_id] = {
                    'partner_pricelist_ids': [],
                    'generic_pricelist_ids': []
                }
            return ret

        return ret

    def _product_price_partner(self, cr, uid, ids, name, arg, context=None):
        # if context is None:
        #     context = {}
        # res = super(product_product, self)._product_price(cr, uid, ids, name, arg, context)
        context = context or self.pool['res.users'].context_get(cr, uid)
        partner_name = context.get('partner_name', False)
        if partner_name:
            partner_obj = self.pool['res.partner']
            partner_ids = partner_obj.search(cr,
                                             uid,
                                             [('name', '=', partner_name)],
                                             context=context)
            if partner_ids:
                partner = partner_obj.browse(cr,
                                             uid,
                                             partner_ids[0],
                                             context=context)
                context[
                    'pricelist'] = partner.property_product_pricelist and partner.property_product_pricelist.id or False
                context['partner'] = partner.id
            else:
                del context['partner_name']
                if 'pricelist' in context:
                    del context['pricelist']
        res = self.pool['product.product']._product_price(
            cr, uid, ids, name, arg, context)
        # res = {}
        # for id in ids:
        #     res.setdefault(id, 0.0)
        return res

    _columns = {
        'partner_id':
        fields.dummy(string='Customer',
                     relation='res.partner',
                     type='many2one',
                     domain=[('customer', '=', True)]),
        'price':
        fields.function(_product_price_partner,
                        type='float',
                        string='Pricelist',
                        digits_compute=dp.get_precision('Sale Price')),
        'partner_pricelist_ids':
        fields.function(_get_all_pricelist_ids,
                        method=True,
                        type='many2many',
                        relation='product.pricelist.version',
                        string='Customer List Price',
                        multi='_get_all_pricelist_ids'),
        'generic_pricelist_ids':
        fields.function(_get_all_pricelist_ids,
                        method=True,
                        type='many2many',
                        relation='product.pricelist.version',
                        string='Customer List Price',
                        multi='_get_all_pricelist_ids'),
    }
コード例 #14
0
ファイル: product.py プロジェクト: 9600-/odoo
class product_product(osv.osv):
    _inherit = "product.product"

    def _stock_move_count(self, cr, uid, ids, field_name, arg, context=None):
        res = dict([(id, {
            'reception_count': 0,
            'delivery_count': 0
        }) for id in ids])
        move_pool = self.pool.get('stock.move')
        moves = move_pool.read_group(
            cr, uid, [('product_id', 'in', ids),
                      ('location_id.usage', '!=', 'internal'),
                      ('location_dest_id.usage', '=', 'internal'),
                      ('state', 'in', ('confirmed', 'assigned', 'pending'))],
            ['product_id'], ['product_id'])
        for move in moves:
            product_id = move['product_id'][0]
            res[product_id]['reception_count'] = move['product_id_count']
        moves = move_pool.read_group(
            cr, uid, [('product_id', 'in', ids),
                      ('location_id.usage', '=', 'internal'),
                      ('location_dest_id.usage', '!=', 'internal'),
                      ('state', 'in', ('confirmed', 'assigned', 'pending'))],
            ['product_id'], ['product_id'])
        for move in moves:
            product_id = move['product_id'][0]
            res[product_id]['delivery_count'] = move['product_id_count']
        return res

    def view_header_get(self, cr, user, view_id, view_type, context=None):
        if context is None:
            context = {}
        res = super(product_product,
                    self).view_header_get(cr, user, view_id, view_type,
                                          context)
        if res: return res
        if (context.get('active_id', False)) and (context.get('active_model')
                                                  == 'stock.location'):
            return _('Products: ') + self.pool.get('stock.location').browse(
                cr, user, context['active_id'], context).name
        return res

    def _get_domain_locations(self, cr, uid, ids, context=None):
        '''
        Parses the context and returns a list of location_ids based on it.
        It will return all stock locations when no parameters are given
        Possible parameters are shop, warehouse, location, force_company, compute_child
        '''
        context = context or {}

        location_obj = self.pool.get('stock.location')
        warehouse_obj = self.pool.get('stock.warehouse')

        location_ids = []
        if context.get('location', False):
            if type(context['location']) == type(1):
                location_ids = [context['location']]
            elif type(context['location']) in (type(''), type(u'')):
                domain = [('complete_name', 'ilike', context['location'])]
                if context.get('force_company', False):
                    domain += [('company_id', '=', context['force_company'])]
                location_ids = location_obj.search(cr,
                                                   uid,
                                                   domain,
                                                   context=context)
            else:
                location_ids = context['location']
        else:
            if context.get('warehouse', False):
                wids = [context['warehouse']]
            else:
                wids = warehouse_obj.search(cr, uid, [], context=context)

            for w in warehouse_obj.browse(cr, uid, wids, context=context):
                location_ids.append(w.view_location_id.id)

        operator = context.get('compute_child', True) and 'child_of' or 'in'
        domain = context.get('force_company', False) and [
            '&', ('company_id', '=', context['force_company'])
        ] or []
        locations = location_obj.browse(cr, uid, location_ids, context=context)
        if operator == "child_of" and locations and locations[
                0].parent_left != 0:
            loc_domain = []
            dest_loc_domain = []
            for loc in locations:
                if loc_domain:
                    loc_domain = ['|'] + loc_domain + [
                        '&',
                        ('location_id.parent_left', '>=', loc.parent_left),
                        ('location_id.parent_left', '<', loc.parent_right)
                    ]
                    dest_loc_domain = ['|'] + dest_loc_domain + [
                        '&',
                        ('location_dest_id.parent_left', '>=',
                         loc.parent_left),
                        ('location_dest_id.parent_left', '<', loc.parent_right)
                    ]
                else:
                    loc_domain += [
                        '&',
                        ('location_id.parent_left', '>=', loc.parent_left),
                        ('location_id.parent_left', '<', loc.parent_right)
                    ]
                    dest_loc_domain += [
                        '&',
                        ('location_dest_id.parent_left', '>=',
                         loc.parent_left),
                        ('location_dest_id.parent_left', '<', loc.parent_right)
                    ]

            return (domain + loc_domain,
                    domain + ['&'] + dest_loc_domain + ['!'] + loc_domain,
                    domain + ['&'] + loc_domain + ['!'] + dest_loc_domain)
        else:
            return (domain + [('location_id', operator, location_ids)],
                    domain + [
                        '&', ('location_dest_id', operator, location_ids), '!',
                        ('location_id', operator, location_ids)
                    ], domain + [
                        '&', ('location_id', operator, location_ids), '!',
                        ('location_dest_id', operator, location_ids)
                    ])

    def _get_domain_dates(self, cr, uid, ids, context):
        from_date = context.get('from_date', False)
        to_date = context.get('to_date', False)
        domain = []
        if from_date:
            domain.append(('date', '>=', from_date))
        if to_date:
            domain.append(('date', '<=', to_date))
        return domain

    def _product_available(self,
                           cr,
                           uid,
                           ids,
                           field_names=None,
                           arg=False,
                           context=None):
        context = context or {}
        field_names = field_names or []

        domain_products = [('product_id', 'in', ids)]
        domain_quant, domain_move_in, domain_move_out = [], [], []
        domain_quant_loc, domain_move_in_loc, domain_move_out_loc = self._get_domain_locations(
            cr, uid, ids, context=context)
        domain_move_in += self._get_domain_dates(
            cr, uid, ids, context=context) + [
                ('state', 'not in', ('done', 'cancel', 'draft'))
            ] + domain_products
        domain_move_out += self._get_domain_dates(
            cr, uid, ids, context=context) + [
                ('state', 'not in', ('done', 'cancel', 'draft'))
            ] + domain_products
        domain_quant += domain_products

        if context.get('lot_id'):
            domain_quant.append(('lot_id', '=', context['lot_id']))
        if context.get('owner_id'):
            domain_quant.append(('owner_id', '=', context['owner_id']))
            owner_domain = ('restrict_partner_id', '=', context['owner_id'])
            domain_move_in.append(owner_domain)
            domain_move_out.append(owner_domain)
        if context.get('package_id'):
            domain_quant.append(('package_id', '=', context['package_id']))

        domain_move_in += domain_move_in_loc
        domain_move_out += domain_move_out_loc
        moves_in = self.pool.get('stock.move').read_group(
            cr,
            uid,
            domain_move_in, ['product_id', 'product_qty'], ['product_id'],
            context=context)
        moves_out = self.pool.get('stock.move').read_group(
            cr,
            uid,
            domain_move_out, ['product_id', 'product_qty'], ['product_id'],
            context=context)

        domain_quant += domain_quant_loc
        quants = self.pool.get('stock.quant').read_group(cr,
                                                         uid,
                                                         domain_quant,
                                                         ['product_id', 'qty'],
                                                         ['product_id'],
                                                         context=context)
        quants = dict(map(lambda x: (x['product_id'][0], x['qty']), quants))

        moves_in = dict(
            map(lambda x: (x['product_id'][0], x['product_qty']), moves_in))
        moves_out = dict(
            map(lambda x: (x['product_id'][0], x['product_qty']), moves_out))
        res = {}
        for product in self.browse(cr, uid, ids, context=context):
            id = product.id
            qty_available = float_round(
                quants.get(id, 0.0),
                precision_rounding=product.uom_id.rounding)
            incoming_qty = float_round(
                moves_in.get(id, 0.0),
                precision_rounding=product.uom_id.rounding)
            outgoing_qty = float_round(
                moves_out.get(id, 0.0),
                precision_rounding=product.uom_id.rounding)
            virtual_available = float_round(
                quants.get(id, 0.0) + moves_in.get(id, 0.0) -
                moves_out.get(id, 0.0),
                precision_rounding=product.uom_id.rounding)
            res[id] = {
                'qty_available': qty_available,
                'incoming_qty': incoming_qty,
                'outgoing_qty': outgoing_qty,
                'virtual_available': virtual_available,
            }
        return res

    def _search_product_quantity(self, cr, uid, obj, name, domain, context):
        res = []
        for field, operator, value in domain:
            #to prevent sql injections
            assert field in ('qty_available', 'virtual_available',
                             'incoming_qty',
                             'outgoing_qty'), 'Invalid domain left operand'
            assert operator in ('<', '>', '=', '!=', '<=',
                                '>='), 'Invalid domain operator'
            assert isinstance(value,
                              (float, int)), 'Invalid domain right operand'

            if operator == '=':
                operator = '=='

            ids = []
            if name == 'qty_available' and (value != 0.0 or operator
                                            not in ('==', '>=', '<=')):
                res.append(('id', 'in',
                            self._search_qty_available(cr, uid, operator,
                                                       value, context)))
            else:
                product_ids = self.search(cr, uid, [], context=context)
                if product_ids:
                    #TODO: Still optimization possible when searching virtual quantities
                    for element in self.browse(cr,
                                               uid,
                                               product_ids,
                                               context=context):
                        if eval(str(element[field]) + operator + str(value)):
                            ids.append(element.id)
                    res.append(('id', 'in', ids))
        return res

    def _search_qty_available(self, cr, uid, operator, value, context):
        domain_quant = []
        if context.get('lot_id'):
            domain_quant.append(('lot_id', '=', context['lot_id']))
        if context.get('owner_id'):
            domain_quant.append(('owner_id', '=', context['owner_id']))
        if context.get('package_id'):
            domain_quant.append(('package_id', '=', context['package_id']))
        domain_quant += self._get_domain_locations(cr,
                                                   uid, [],
                                                   context=context)[0]
        quants = self.pool.get('stock.quant').read_group(cr,
                                                         uid,
                                                         domain_quant,
                                                         ['product_id', 'qty'],
                                                         ['product_id'],
                                                         context=context)
        quants = dict(map(lambda x: (x['product_id'][0], x['qty']), quants))
        quants = dict((k, v) for k, v in quants.iteritems()
                      if eval(str(v) + operator + str(value)))
        return (list(quants))

    def _product_available_text(self,
                                cr,
                                uid,
                                ids,
                                field_names=None,
                                arg=False,
                                context=None):
        res = {}
        for product in self.browse(cr, uid, ids, context=context):
            res[product.id] = str(product.qty_available) + _(" On Hand")
        return res

    def _compute_nbr_reordering_rules(self,
                                      cr,
                                      uid,
                                      ids,
                                      field_names=None,
                                      arg=None,
                                      context=None):
        res = dict.fromkeys(
            ids, {
                'nbr_reordering_rules': 0,
                'reordering_min_qty': 0,
                'reordering_max_qty': 0
            })
        product_data = self.pool['stock.warehouse.orderpoint'].read_group(
            cr,
            uid, [('product_id', 'in', ids)],
            ['product_id', 'product_min_qty', 'product_max_qty'],
            ['product_id'],
            context=context)
        for data in product_data:
            res[data['product_id'][0]]['nbr_reordering_rules'] = int(
                data['product_id_count'])
            res[data['product_id']
                [0]]['reordering_min_qty'] = data['product_min_qty']
            res[data['product_id']
                [0]]['reordering_max_qty'] = data['product_max_qty']
        return res

    _columns = {
        'reception_count':
        fields.function(_stock_move_count,
                        string="Receipt",
                        type='integer',
                        multi='pickings'),
        'delivery_count':
        fields.function(_stock_move_count,
                        string="Delivery",
                        type='integer',
                        multi='pickings'),
        'qty_available':
        fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Quantity On Hand',
            fnct_search=_search_product_quantity,
            help="Current quantity of products.\n"
            "In a context with a single Stock Location, this includes "
            "goods stored at this Location, or any of its children.\n"
            "In a context with a single Warehouse, this includes "
            "goods stored in the Stock Location of this Warehouse, or any "
            "of its children.\n"
            "stored in the Stock Location of the Warehouse of this Shop, "
            "or any of its children.\n"
            "Otherwise, this includes goods stored in any Stock Location "
            "with 'internal' type."),
        'qty_available2':
        fields.related('qty_available',
                       type="float",
                       relation="product.product",
                       string="On Hand"),
        'virtual_available':
        fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Forecast Quantity',
            fnct_search=_search_product_quantity,
            help="Forecast quantity (computed as Quantity On Hand "
            "- Outgoing + Incoming)\n"
            "In a context with a single Stock Location, this includes "
            "goods stored in this location, or any of its children.\n"
            "In a context with a single Warehouse, this includes "
            "goods stored in the Stock Location of this Warehouse, or any "
            "of its children.\n"
            "Otherwise, this includes goods stored in any Stock Location "
            "with 'internal' type."),
        'incoming_qty':
        fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Incoming',
            fnct_search=_search_product_quantity,
            help="Quantity of products that are planned to arrive.\n"
            "In a context with a single Stock Location, this includes "
            "goods arriving to this Location, or any of its children.\n"
            "In a context with a single Warehouse, this includes "
            "goods arriving to the Stock Location of this Warehouse, or "
            "any of its children.\n"
            "Otherwise, this includes goods arriving to any Stock "
            "Location with 'internal' type."),
        'outgoing_qty':
        fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Outgoing',
            fnct_search=_search_product_quantity,
            help="Quantity of products that are planned to leave.\n"
            "In a context with a single Stock Location, this includes "
            "goods leaving this Location, or any of its children.\n"
            "In a context with a single Warehouse, this includes "
            "goods leaving the Stock Location of this Warehouse, or "
            "any of its children.\n"
            "Otherwise, this includes goods leaving any Stock "
            "Location with 'internal' type."),
        'location_id':
        fields.dummy(string='Location',
                     relation='stock.location',
                     type='many2one'),
        'warehouse_id':
        fields.dummy(string='Warehouse',
                     relation='stock.warehouse',
                     type='many2one'),
        'orderpoint_ids':
        fields.one2many('stock.warehouse.orderpoint', 'product_id',
                        'Minimum Stock Rules'),
        'nbr_reordering_rules':
        fields.function(_compute_nbr_reordering_rules,
                        string='Reordering Rules',
                        type='integer',
                        multi=True),
        'reordering_min_qty':
        fields.function(_compute_nbr_reordering_rules,
                        type='float',
                        multi=True),
        'reordering_max_qty':
        fields.function(_compute_nbr_reordering_rules,
                        type='float',
                        multi=True),
    }

    def fields_view_get(self,
                        cr,
                        uid,
                        view_id=None,
                        view_type='form',
                        context=None,
                        toolbar=False,
                        submenu=False):
        res = super(product_product, self).fields_view_get(cr,
                                                           uid,
                                                           view_id=view_id,
                                                           view_type=view_type,
                                                           context=context,
                                                           toolbar=toolbar,
                                                           submenu=submenu)
        if context is None:
            context = {}
        if ('location' in context) and context['location']:
            location_info = self.pool.get('stock.location').browse(
                cr, uid, context['location'])
            fields = res.get('fields', {})
            if fields:
                if location_info.usage == 'supplier':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Receipts')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Received Qty')

                if location_info.usage == 'internal':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Forecasted Quantity')

                if location_info.usage == 'customer':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Deliveries')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Delivered Qty')

                if location_info.usage == 'inventory':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future P&L')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _('P&L Qty')

                if location_info.usage == 'procurement':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Qty')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Unplanned Qty')

                if location_info.usage == 'production':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Productions')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Produced Qty')
        return res

    def action_view_routes(self, cr, uid, ids, context=None):
        template_obj = self.pool.get("product.template")
        templ_ids = list(
            set([
                x.product_tmpl_id.id
                for x in self.browse(cr, uid, ids, context=context)
            ]))
        return template_obj.action_view_routes(cr,
                                               uid,
                                               templ_ids,
                                               context=context)

    def onchange_tracking(self, cr, uid, ids, tracking, context=None):
        if not tracking or tracking == 'none':
            return {}
        unassigned_quants = self.pool['stock.quant'].search_count(
            cr,
            uid, [('product_id', 'in', ids), ('lot_id', '=', False),
                  ('location_id.usage', '=', 'internal')],
            context=context)
        if unassigned_quants:
            return {
                'warning': {
                    'title':
                    _('Warning!'),
                    'message':
                    _("You have products in stock that have no lot number.  You can assign serial numbers by doing an inventory.  "
                      )
                }
            }
        return {}
コード例 #15
0
ファイル: product.py プロジェクト: CamiloRamirez90/odoo-1
class product_product(osv.osv):
    _inherit = "product.product"

    def _stock_move_count(self, cr, uid, ids, field_name, arg, context=None):
        res = dict([(id, {
            'reception_count': 0,
            'delivery_count': 0
        }) for id in ids])
        move_pool = self.pool.get('stock.move')
        moves = move_pool.read_group(
            cr, uid, [('product_id', 'in', ids),
                      ('location_id.usage', '!=', 'internal'),
                      ('location_dest_id.usage', '=', 'internal'),
                      ('state', 'in', ('confirmed', 'assigned', 'pending'))],
            ['product_id'], ['product_id'])
        for move in moves:
            product_id = move['product_id'][0]
            res[product_id]['reception_count'] = move['product_id_count']
        moves = move_pool.read_group(
            cr, uid, [('product_id', 'in', ids),
                      ('location_id.usage', '=', 'internal'),
                      ('location_dest_id.usage', '!=', 'internal'),
                      ('state', 'in', ('confirmed', 'assigned', 'pending'))],
            ['product_id'], ['product_id'])
        for move in moves:
            product_id = move['product_id'][0]
            res[product_id]['delivery_count'] = move['product_id_count']
        return res

    def view_header_get(self, cr, user, view_id, view_type, context=None):
        if context is None:
            context = {}
        res = super(product_product,
                    self).view_header_get(cr, user, view_id, view_type,
                                          context)
        if res: return res
        if (context.get('active_id', False)) and (context.get('active_model')
                                                  == 'stock.location'):
            return _('Products: ') + self.pool.get('stock.location').browse(
                cr, user, context['active_id'], context).name
        return res

    def _get_domain_locations(self, cr, uid, ids, context=None):
        '''
        Parses the context and returns a list of location_ids based on it.
        It will return all stock locations when no parameters are given
        Possible parameters are shop, warehouse, location, force_company, compute_child
        '''
        context = context or {}

        location_obj = self.pool.get('stock.location')
        warehouse_obj = self.pool.get('stock.warehouse')

        location_ids = []
        if context.get('location', False):
            if type(context['location']) == type(1):
                location_ids = [context['location']]
            elif type(context['location']) in (type(''), type(u'')):
                domain = [('complete_name', 'ilike', context['location'])]
                if context.get('force_company', False):
                    domain += [('company_id', '=', context['force_company'])]
                location_ids = location_obj.search(cr,
                                                   uid,
                                                   domain,
                                                   context=context)
            else:
                location_ids = context['location']
        else:
            if context.get('warehouse', False):
                wids = [context['warehouse']]
            else:
                wids = warehouse_obj.search(cr, uid, [], context=context)

            for w in warehouse_obj.browse(cr, uid, wids, context=context):
                location_ids.append(w.view_location_id.id)

        operator = context.get('compute_child', True) and 'child_of' or 'in'
        domain = context.get('force_company', False) and [
            '&', ('company_id', '=', context['force_company'])
        ] or []
        return (domain + [('location_id', operator, location_ids)], domain + [
            '&', ('location_dest_id', operator, location_ids), '!',
            ('location_id', operator, location_ids)
        ], domain + [
            '&', ('location_id', operator, location_ids), '!',
            ('location_dest_id', operator, location_ids)
        ])

    def _get_domain_dates(self, cr, uid, ids, context):
        from_date = context.get('from_date', False)
        to_date = context.get('to_date', False)
        domain = []
        if from_date:
            domain.append(('date', '>=', from_date))
        if to_date:
            domain.append(('date', '<=', to_date))
        return domain

    def _product_available(self,
                           cr,
                           uid,
                           ids,
                           field_names=None,
                           arg=False,
                           context=None):
        context = context or {}
        field_names = field_names or []

        domain_products = [('product_id', 'in', ids)]
        domain_quant, domain_move_in, domain_move_out = self._get_domain_locations(
            cr, uid, ids, context=context)
        domain_move_in += self._get_domain_dates(
            cr, uid, ids, context=context) + [
                ('state', 'not in', ('done', 'cancel'))
            ] + domain_products
        domain_move_out += self._get_domain_dates(
            cr, uid, ids, context=context) + [
                ('state', 'not in', ('done', 'cancel'))
            ] + domain_products
        domain_quant += domain_products
        if context.get('lot_id') or context.get('owner_id') or context.get(
                'package_id'):
            if context.get('lot_id'):
                domain_quant.append(('lot_id', '=', context['lot_id']))
            if context.get('owner_id'):
                domain_quant.append(('owner_id', '=', context['owner_id']))
            if context.get('package_id'):
                domain_quant.append(('package_id', '=', context['package_id']))
            moves_in = []
            moves_out = []
        else:
            moves_in = self.pool.get('stock.move').read_group(
                cr,
                uid,
                domain_move_in, ['product_id', 'product_qty'], ['product_id'],
                context=context)
            moves_out = self.pool.get('stock.move').read_group(
                cr,
                uid,
                domain_move_out, ['product_id', 'product_qty'], ['product_id'],
                context=context)

        quants = self.pool.get('stock.quant').read_group(cr,
                                                         uid,
                                                         domain_quant,
                                                         ['product_id', 'qty'],
                                                         ['product_id'],
                                                         context=context)
        quants = dict(map(lambda x: (x['product_id'][0], x['qty']), quants))

        moves_in = dict(
            map(lambda x: (x['product_id'][0], x['product_qty']), moves_in))
        moves_out = dict(
            map(lambda x: (x['product_id'][0], x['product_qty']), moves_out))
        res = {}
        for id in ids:
            res[id] = {
                'qty_available':
                quants.get(id, 0.0),
                'incoming_qty':
                moves_in.get(id, 0.0),
                'outgoing_qty':
                moves_out.get(id, 0.0),
                'virtual_available':
                quants.get(id, 0.0) + moves_in.get(id, 0.0) -
                moves_out.get(id, 0.0),
            }

        return res

    def _search_product_quantity(self, cr, uid, obj, name, domain, context):
        res = []
        for field, operator, value in domain:
            #to prevent sql injections
            assert field in ('qty_available', 'virtual_available',
                             'incoming_qty',
                             'outgoing_qty'), 'Invalid domain left operand'
            assert operator in ('<', '>', '=', '!=', '<=',
                                '>='), 'Invalid domain operator'
            assert isinstance(value,
                              (float, int)), 'Invalid domain right operand'

            if operator == '=':
                operator = '=='

            product_ids = self.search(cr, uid, [], context=context)
            ids = []
            if product_ids:
                #TODO: use a query instead of this browse record which is probably making the too much requests, but don't forget
                #the context that can be set with a location, an owner...
                for element in self.browse(cr,
                                           uid,
                                           product_ids,
                                           context=context):
                    if eval(str(element[field]) + operator + str(value)):
                        ids.append(element.id)
            res.append(('id', 'in', ids))
        return res

    def _product_available_text(self,
                                cr,
                                uid,
                                ids,
                                field_names=None,
                                arg=False,
                                context=None):
        res = {}
        for product in self.browse(cr, uid, ids, context=context):
            res[product.id] = str(product.qty_available) + _(" On Hand")
        return res

    _columns = {
        'reception_count':
        fields.function(_stock_move_count,
                        string="Receipt",
                        type='integer',
                        multi='pickings'),
        'delivery_count':
        fields.function(_stock_move_count,
                        string="Delivery",
                        type='integer',
                        multi='pickings'),
        'qty_available':
        fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Quantity On Hand',
            fnct_search=_search_product_quantity,
            help="Current quantity of products.\n"
            "In a context with a single Stock Location, this includes "
            "goods stored at this Location, or any of its children.\n"
            "In a context with a single Warehouse, this includes "
            "goods stored in the Stock Location of this Warehouse, or any "
            "of its children.\n"
            "stored in the Stock Location of the Warehouse of this Shop, "
            "or any of its children.\n"
            "Otherwise, this includes goods stored in any Stock Location "
            "with 'internal' type."),
        'qty_available2':
        fields.related('qty_available',
                       type="float",
                       relation="product.product",
                       string="On Hand"),
        'virtual_available':
        fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Forecast Quantity',
            fnct_search=_search_product_quantity,
            help="Forecast quantity (computed as Quantity On Hand "
            "- Outgoing + Incoming)\n"
            "In a context with a single Stock Location, this includes "
            "goods stored in this location, or any of its children.\n"
            "In a context with a single Warehouse, this includes "
            "goods stored in the Stock Location of this Warehouse, or any "
            "of its children.\n"
            "Otherwise, this includes goods stored in any Stock Location "
            "with 'internal' type."),
        'incoming_qty':
        fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Incoming',
            fnct_search=_search_product_quantity,
            help="Quantity of products that are planned to arrive.\n"
            "In a context with a single Stock Location, this includes "
            "goods arriving to this Location, or any of its children.\n"
            "In a context with a single Warehouse, this includes "
            "goods arriving to the Stock Location of this Warehouse, or "
            "any of its children.\n"
            "Otherwise, this includes goods arriving to any Stock "
            "Location with 'internal' type."),
        'outgoing_qty':
        fields.function(
            _product_available,
            multi='qty_available',
            type='float',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Outgoing',
            fnct_search=_search_product_quantity,
            help="Quantity of products that are planned to leave.\n"
            "In a context with a single Stock Location, this includes "
            "goods leaving this Location, or any of its children.\n"
            "In a context with a single Warehouse, this includes "
            "goods leaving the Stock Location of this Warehouse, or "
            "any of its children.\n"
            "Otherwise, this includes goods leaving any Stock "
            "Location with 'internal' type."),
        'location_id':
        fields.dummy(string='Location',
                     relation='stock.location',
                     type='many2one'),
        'warehouse_id':
        fields.dummy(string='Warehouse',
                     relation='stock.warehouse',
                     type='many2one'),
        'orderpoint_ids':
        fields.one2many('stock.warehouse.orderpoint', 'product_id',
                        'Minimum Stock Rules'),
    }

    def fields_view_get(self,
                        cr,
                        uid,
                        view_id=None,
                        view_type='form',
                        context=None,
                        toolbar=False,
                        submenu=False):
        res = super(product_product, self).fields_view_get(cr,
                                                           uid,
                                                           view_id,
                                                           view_type,
                                                           context,
                                                           toolbar=toolbar,
                                                           submenu=submenu)
        if context is None:
            context = {}
        if ('location' in context) and context['location']:
            location_info = self.pool.get('stock.location').browse(
                cr, uid, context['location'])
            fields = res.get('fields', {})
            if fields:
                if location_info.usage == 'supplier':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Receipts')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Received Qty')

                if location_info.usage == 'internal':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Stock')

                if location_info.usage == 'customer':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Deliveries')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Delivered Qty')

                if location_info.usage == 'inventory':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future P&L')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _('P&L Qty')

                if location_info.usage == 'procurement':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Qty')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Unplanned Qty')

                if location_info.usage == 'production':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Productions')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Produced Qty')
        return res

    def action_view_routes(self, cr, uid, ids, context=None):
        template_obj = self.pool.get("product.template")
        templ_ids = list(
            set([
                x.product_tmpl_id.id
                for x in self.browse(cr, uid, ids, context=context)
            ]))
        return template_obj.action_view_routes(cr,
                                               uid,
                                               templ_ids,
                                               context=context)
コード例 #16
0
ファイル: product.py プロジェクト: tedi3231/openerp
class product_product(osv.osv):
    _inherit = "product.product"

    def _stock_move_count(self, cr, uid, ids, field_name, arg, context=None):
        res = dict([(id, {
            'reception_count': 0,
            'delivery_count': 0
        }) for id in ids])
        move_pool = self.pool.get('stock.move')
        moves = move_pool.read_group(cr, uid,
                                     [('product_id', 'in', ids),
                                      ('picking_id.type', '=', 'in'),
                                      ('state', 'in',
                                       ('confirmed', 'assigned', 'pending'))],
                                     ['product_id'], ['product_id'])
        for move in moves:
            product_id = move['product_id'][0]
            res[product_id]['reception_count'] = move['product_id_count']
        moves = move_pool.read_group(cr, uid,
                                     [('product_id', 'in', ids),
                                      ('picking_id.type', '=', 'out'),
                                      ('state', 'in',
                                       ('confirmed', 'assigned', 'pending'))],
                                     ['product_id'], ['product_id'])
        for move in moves:
            product_id = move['product_id'][0]
            res[product_id]['delivery_count'] = move['product_id_count']
        return res

    def get_product_accounts(self, cr, uid, product_id, context=None):
        """ To get the stock input account, stock output account and stock journal related to product.
        @param product_id: product id
        @return: dictionary which contains information regarding stock input account, stock output account and stock journal
        """
        if context is None:
            context = {}
        product_obj = self.pool.get('product.product').browse(cr,
                                                              uid,
                                                              product_id,
                                                              context=context)

        stock_input_acc = product_obj.property_stock_account_input and product_obj.property_stock_account_input.id or False
        if not stock_input_acc:
            stock_input_acc = product_obj.categ_id.property_stock_account_input_categ and product_obj.categ_id.property_stock_account_input_categ.id or False

        stock_output_acc = product_obj.property_stock_account_output and product_obj.property_stock_account_output.id or False
        if not stock_output_acc:
            stock_output_acc = product_obj.categ_id.property_stock_account_output_categ and product_obj.categ_id.property_stock_account_output_categ.id or False

        journal_id = product_obj.categ_id.property_stock_journal and product_obj.categ_id.property_stock_journal.id or False
        account_valuation = product_obj.categ_id.property_stock_valuation_account_id and product_obj.categ_id.property_stock_valuation_account_id.id or False
        return {
            'stock_account_input': stock_input_acc,
            'stock_account_output': stock_output_acc,
            'stock_journal': journal_id,
            'property_stock_valuation_account_id': account_valuation
        }

    def do_change_standard_price(self, cr, uid, ids, datas, context=None):
        """ Changes the Standard Price of Product and creates an account move accordingly.
        @param datas : dict. contain default datas like new_price, stock_output_account, stock_input_account, stock_journal
        @param context: A standard dictionary
        @return:

        """
        location_obj = self.pool.get('stock.location')
        move_obj = self.pool.get('account.move')
        move_line_obj = self.pool.get('account.move.line')
        if context is None:
            context = {}

        new_price = datas.get('new_price', 0.0)
        stock_output_acc = datas.get('stock_output_account', False)
        stock_input_acc = datas.get('stock_input_account', False)
        journal_id = datas.get('stock_journal', False)
        product_obj = self.browse(cr, uid, ids, context=context)[0]
        account_valuation = product_obj.categ_id.property_stock_valuation_account_id
        account_valuation_id = account_valuation and account_valuation.id or False
        if not account_valuation_id:
            raise osv.except_osv(
                _('Error!'),
                _('Specify valuation Account for Product Category: %s.') %
                (product_obj.categ_id.name))
        move_ids = []
        loc_ids = location_obj.search(cr, uid, [('usage', '=', 'internal')])
        for rec_id in ids:
            for location in location_obj.browse(cr,
                                                uid,
                                                loc_ids,
                                                context=context):
                c = context.copy()
                c.update({'location': location.id, 'compute_child': False})

                product = self.browse(cr, uid, rec_id, context=c)
                qty = product.qty_available
                diff = product.standard_price - new_price
                if not diff:
                    raise osv.except_osv(
                        _('Error!'),
                        _("No difference between standard price and new price!"
                          ))
                if qty:
                    company_id = location.company_id and location.company_id.id or False
                    if not company_id:
                        raise osv.except_osv(
                            _('Error!'),
                            _('Please specify company in Location.'))
                    #
                    # Accounting Entries
                    #
                    if not journal_id:
                        journal_id = product.categ_id.property_stock_journal and product.categ_id.property_stock_journal.id or False
                    if not journal_id:
                        raise osv.except_osv(_('Error!'),
                            _('Please define journal '\
                              'on the product category: "%s" (id: %d).') % \
                                (product.categ_id.name,
                                    product.categ_id.id,))
                    move_id = move_obj.create(cr, uid, {
                        'journal_id': journal_id,
                        'company_id': company_id
                    })

                    move_ids.append(move_id)

                    if diff > 0:
                        if not stock_input_acc:
                            stock_input_acc = product.\
                                property_stock_account_input.id
                        if not stock_input_acc:
                            stock_input_acc = product.categ_id.\
                                    property_stock_account_input_categ.id
                        if not stock_input_acc:
                            raise osv.except_osv(_('Error!'),
                                    _('Please define stock input account ' \
                                            'for this product: "%s" (id: %d).') % \
                                            (product.name,
                                                product.id,))
                        amount_diff = qty * diff
                        move_line_obj.create(
                            cr, uid, {
                                'name': product.name,
                                'account_id': stock_input_acc,
                                'debit': amount_diff,
                                'move_id': move_id,
                            })
                        move_line_obj.create(
                            cr, uid, {
                                'name': product.categ_id.name,
                                'account_id': account_valuation_id,
                                'credit': amount_diff,
                                'move_id': move_id
                            })
                    elif diff < 0:
                        if not stock_output_acc:
                            stock_output_acc = product.\
                                property_stock_account_output.id
                        if not stock_output_acc:
                            stock_output_acc = product.categ_id.\
                                    property_stock_account_output_categ.id
                        if not stock_output_acc:
                            raise osv.except_osv(_('Error!'),
                                    _('Please define stock output account ' \
                                            'for this product: "%s" (id: %d).') % \
                                            (product.name,
                                                product.id,))
                        amount_diff = qty * -diff
                        move_line_obj.create(
                            cr, uid, {
                                'name': product.name,
                                'account_id': stock_output_acc,
                                'credit': amount_diff,
                                'move_id': move_id
                            })
                        move_line_obj.create(
                            cr, uid, {
                                'name': product.categ_id.name,
                                'account_id': account_valuation_id,
                                'debit': amount_diff,
                                'move_id': move_id
                            })

            self.write(cr, uid, rec_id, {'standard_price': new_price})

        return move_ids

    def view_header_get(self, cr, user, view_id, view_type, context=None):
        if context is None:
            context = {}
        res = super(product_product,
                    self).view_header_get(cr, user, view_id, view_type,
                                          context)
        if res: return res
        if (context.get('active_id', False)) and (context.get('active_model')
                                                  == 'stock.location'):
            return _('Products: ') + self.pool.get('stock.location').browse(
                cr, user, context['active_id'], context).name
        return res

    def get_product_available(self, cr, uid, ids, context=None):
        """ Finds whether product is available or not in particular warehouse.
        @return: Dictionary of values
        """
        if context is None:
            context = {}

        location_obj = self.pool.get('stock.location')
        warehouse_obj = self.pool.get('stock.warehouse')
        shop_obj = self.pool.get('sale.shop')

        states = context.get('states', [])
        what = context.get('what', ())
        if not ids:
            ids = self.search(cr, uid, [])
        res = {}.fromkeys(ids, 0.0)
        if not ids:
            return res

        if context.get('shop', False):
            warehouse_id = shop_obj.read(cr, uid, int(context['shop']),
                                         ['warehouse_id'])['warehouse_id'][0]
            if warehouse_id:
                context['warehouse'] = warehouse_id

        if context.get('warehouse', False):
            lot_id = warehouse_obj.read(cr, uid, int(context['warehouse']),
                                        ['lot_stock_id'])['lot_stock_id'][0]
            if lot_id:
                context['location'] = lot_id

        if context.get('location', False):
            if type(context['location']) == type(1):
                location_ids = [context['location']]
            elif type(context['location']) in (type(''), type(u'')):
                location_ids = location_obj.search(
                    cr,
                    uid, [('name', 'ilike', context['location'])],
                    context=context)
            else:
                location_ids = context['location']
        else:
            location_ids = []
            wids = warehouse_obj.search(cr, uid, [], context=context)
            for w in warehouse_obj.browse(cr, uid, wids, context=context):
                location_ids.append(w.lot_stock_id.id)

        # build the list of ids of children of the location given by id
        if context.get('compute_child', True):
            child_location_ids = location_obj.search(
                cr, uid, [('location_id', 'child_of', location_ids)])
            location_ids = child_location_ids or location_ids

        # this will be a dictionary of the product UoM by product id
        product2uom = {}
        uom_ids = []
        for product in self.read(cr, uid, ids, ['uom_id'], context=context):
            product2uom[product['id']] = product['uom_id'][0]
            uom_ids.append(product['uom_id'][0])
        # this will be a dictionary of the UoM resources we need for conversion purposes, by UoM id
        uoms_o = {}
        for uom in self.pool.get('product.uom').browse(cr,
                                                       uid,
                                                       uom_ids,
                                                       context=context):
            uoms_o[uom.id] = uom

        results = []
        results2 = []

        from_date = context.get('from_date', False)
        to_date = context.get('to_date', False)
        date_str = False
        date_values = False
        where = [
            tuple(location_ids),
            tuple(location_ids),
            tuple(ids),
            tuple(states)
        ]
        if from_date and to_date:
            date_str = "date>=%s and date<=%s"
            where.append(tuple([from_date]))
            where.append(tuple([to_date]))
        elif from_date:
            date_str = "date>=%s"
            date_values = [from_date]
        elif to_date:
            date_str = "date<=%s"
            date_values = [to_date]
        if date_values:
            where.append(tuple(date_values))

        prodlot_id = context.get('prodlot_id', False)
        prodlot_clause = ''
        if prodlot_id:
            prodlot_clause = ' and prodlot_id = %s '
            where += [prodlot_id]

        # TODO: perhaps merge in one query.
        if 'in' in what:
            # all moves from a location out of the set to a location in the set
            cr.execute(
                'select sum(product_qty), product_id, product_uom '\
                'from stock_move '\
                'where location_id NOT IN %s '\
                'and location_dest_id IN %s '\
                'and product_id IN %s '\
                'and state IN %s ' + (date_str and 'and '+date_str+' ' or '') +' '\
                + prodlot_clause +
                'group by product_id,product_uom',tuple(where))
            results = cr.fetchall()
        if 'out' in what:
            # all moves from a location in the set to a location out of the set
            cr.execute(
                'select sum(product_qty), product_id, product_uom '\
                'from stock_move '\
                'where location_id IN %s '\
                'and location_dest_id NOT IN %s '\
                'and product_id  IN %s '\
                'and state in %s ' + (date_str and 'and '+date_str+' ' or '') + ' '\
                + prodlot_clause +
                'group by product_id,product_uom',tuple(where))
            results2 = cr.fetchall()

        # Get the missing UoM resources
        uom_obj = self.pool.get('product.uom')
        uoms = map(lambda x: x[2], results) + map(lambda x: x[2], results2)
        if context.get('uom', False):
            uoms += [context['uom']]
        uoms = filter(lambda x: x not in uoms_o.keys(), uoms)
        if uoms:
            uoms = uom_obj.browse(cr, uid, list(set(uoms)), context=context)
            for o in uoms:
                uoms_o[o.id] = o

        #TOCHECK: before change uom of product, stock move line are in old uom.
        context.update({'raise-exception': False})
        # Count the incoming quantities
        for amount, prod_id, prod_uom in results:
            amount = uom_obj._compute_qty_obj(cr,
                                              uid,
                                              uoms_o[prod_uom],
                                              amount,
                                              uoms_o[context.get('uom', False)
                                                     or product2uom[prod_id]],
                                              context=context)
            res[prod_id] += amount
        # Count the outgoing quantities
        for amount, prod_id, prod_uom in results2:
            amount = uom_obj._compute_qty_obj(cr,
                                              uid,
                                              uoms_o[prod_uom],
                                              amount,
                                              uoms_o[context.get('uom', False)
                                                     or product2uom[prod_id]],
                                              context=context)
            res[prod_id] -= amount
        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
        """
        if not field_names:
            field_names = []
        if context is None:
            context = {}
        res = {}
        for id in ids:
            res[id] = {}.fromkeys(field_names, 0.0)
        for f in field_names:
            c = context.copy()
            if f == 'qty_available':
                c.update({'states': ('done', ), 'what': ('in', 'out')})
            if f == 'virtual_available':
                c.update({
                    'states': ('confirmed', 'waiting', 'assigned', 'done'),
                    'what': ('in', 'out')
                })
            if f == 'incoming_qty':
                c.update({
                    'states': ('confirmed', 'waiting', 'assigned'),
                    'what': ('in', )
                })
            if f == 'outgoing_qty':
                c.update({
                    'states': ('confirmed', 'waiting', 'assigned'),
                    'what': ('out', )
                })
            stock = self.get_product_available(cr, uid, ids, context=c)
            for id in ids:
                res[id][f] = stock.get(id, 0.0)
        return res

    _columns = {
        'reception_count': fields.function(_stock_move_count, string="Reception", type='integer', multi='pickings'),
        'delivery_count': fields.function(_stock_move_count, string="Delivery", type='integer', multi='pickings'),
        'qty_available': fields.function(_product_available, multi='qty_available',
            type='float',  digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Quantity On Hand',
            help="Current quantity of products.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods stored at this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods stored in the Stock Location of this Warehouse, or any "
                 "of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "stored in the Stock Location of the Warehouse of this Shop, "
                 "or any of its children.\n"
                 "Otherwise, this includes goods stored in any Stock Location "
                 "with 'internal' type."),
        'virtual_available': fields.function(_product_available, multi='qty_available',
            type='float',  digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Forecasted Quantity',
            help="Forecast quantity (computed as Quantity On Hand "
                 "- Outgoing + Incoming)\n"
                 "In a context with a single Stock Location, this includes "
                 "goods stored in this location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods stored in the Stock Location of this Warehouse, or any "
                 "of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "stored in the Stock Location of the Warehouse of this Shop, "
                 "or any of its children.\n"
                 "Otherwise, this includes goods stored in any Stock Location "
                 "with 'internal' type."),
        'incoming_qty': fields.function(_product_available, multi='qty_available',
            type='float',  digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Incoming',
            help="Quantity of products that are planned to arrive.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods arriving to this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods arriving to the Stock Location of this Warehouse, or "
                 "any of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "arriving to the Stock Location of the Warehouse of this "
                 "Shop, or any of its children.\n"
                 "Otherwise, this includes goods arriving to any Stock "
                 "Location with 'internal' type."),
        'outgoing_qty': fields.function(_product_available, multi='qty_available',
            type='float',  digits_compute=dp.get_precision('Product Unit of Measure'),
            string='Outgoing',
            help="Quantity of products that are planned to leave.\n"
                 "In a context with a single Stock Location, this includes "
                 "goods leaving this Location, or any of its children.\n"
                 "In a context with a single Warehouse, this includes "
                 "goods leaving the Stock Location of this Warehouse, or "
                 "any of its children.\n"
                 "In a context with a single Shop, this includes goods "
                 "leaving the Stock Location of the Warehouse of this "
                 "Shop, or any of its children.\n"
                 "Otherwise, this includes goods leaving any Stock "
                 "Location with 'internal' type."),
        'track_production': fields.boolean('Track Manufacturing Lots', help="Forces to specify a Serial Number for all moves containing this product and generated by a Manufacturing Order"),
        'track_incoming': fields.boolean('Track Incoming Lots', help="Forces to specify a Serial Number for all moves containing this product and coming from a Supplier Location"),
        'track_outgoing': fields.boolean('Track Outgoing Lots', help="Forces to specify a Serial Number for all moves containing this product and going to a Customer Location"),
        'location_id': fields.dummy(string='Location', relation='stock.location', type='many2one'),
        'warehouse_id': fields.dummy(string='Warehouse', relation='stock.warehouse', type='many2one'),
        'valuation':fields.selection([('manual_periodic', 'Periodical (manual)'),
                                        ('real_time','Real Time (automated)'),], 'Inventory Valuation',
                                        help="If real-time valuation is enabled for a product, the system will automatically write journal entries corresponding to stock moves." \
                                             "The inventory variation account set on the product category will represent the current inventory value, and the stock input and stock output account will hold the counterpart moves for incoming and outgoing products."
                                        , required=True),
    }

    _defaults = {
        'valuation': 'manual_periodic',
    }

    def fields_view_get(self,
                        cr,
                        uid,
                        view_id=None,
                        view_type='form',
                        context=None,
                        toolbar=False,
                        submenu=False):
        res = super(product_product, self).fields_view_get(cr,
                                                           uid,
                                                           view_id,
                                                           view_type,
                                                           context,
                                                           toolbar=toolbar,
                                                           submenu=submenu)
        if context is None:
            context = {}
        if ('location' in context) and context['location']:
            location_info = self.pool.get('stock.location').browse(
                cr, uid, context['location'])
            fields = res.get('fields', {})
            if fields:
                if location_info.usage == 'supplier':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Receptions')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Received Qty')

                if location_info.usage == 'internal':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Stock')

                if location_info.usage == 'customer':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Deliveries')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Delivered Qty')

                if location_info.usage == 'inventory':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future P&L')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _('P&L Qty')

                if location_info.usage == 'procurement':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Qty')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Unplanned Qty')

                if location_info.usage == 'production':
                    if fields.get('virtual_available'):
                        res['fields']['virtual_available']['string'] = _(
                            'Future Productions')
                    if fields.get('qty_available'):
                        res['fields']['qty_available']['string'] = _(
                            'Produced Qty')
        return res
コード例 #17
0
class product_product(osv.osv):
    def view_header_get(self, cr, uid, view_id, view_type, context=None):
        if context is None:
            context = {}
        res = super(product_product, self).view_header_get(cr, uid, view_id, view_type, context)
        if (context.get('categ_id', False)):
            return _('Products: ') + self.pool.get('product.category').browse(cr, uid, context['categ_id'], context=context).name
        return res

    def _product_price(self, cr, uid, ids, name, arg, context=None):
        res = {}
        if context is None:
            context = {}
        quantity = context.get('quantity') or 1.0
        pricelist = context.get('pricelist', False)
        partner = context.get('partner', False)
        if pricelist:
            for id in ids:
                try:
                    price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist], id, quantity, partner=partner, context=context)[pricelist]
                except:
                    price = 0.0
                res[id] = price
        for id in ids:
            res.setdefault(id, 0.0)
        return res

    def _get_product_available_func(states, what):
        def _product_available(self, cr, uid, ids, name, arg, context=None):
            return {}.fromkeys(ids, 0.0)
        return _product_available

    _product_qty_available = _get_product_available_func(('done',), ('in', 'out'))
    _product_virtual_available = _get_product_available_func(('confirmed', 'waiting', 'assigned', 'done'), ('in', 'out'))
    _product_outgoing_qty = _get_product_available_func(('confirmed', 'waiting', 'assigned'), ('out',))
    _product_incoming_qty = _get_product_available_func(('confirmed', 'waiting', 'assigned'), ('in',))

    def _product_lst_price(self, cr, uid, ids, name, arg, context=None):
        res = {}
        product_uom_obj = self.pool.get('product.uom')
        for id in ids:
            res.setdefault(id, 0.0)
        for product in self.browse(cr, uid, ids, context=context):
            if 'uom' in context:
                uom = product.uos_id or product.uom_id
                res[product.id] = product_uom_obj._compute_price(cr, uid,
                        uom.id, product.list_price, context['uom'])
            else:
                res[product.id] = product.list_price
            res[product.id] = (res[product.id] or 0.0) * (product.price_margin or 1.0) + product.price_extra
        return res

    def _get_partner_code_name(self, cr, uid, ids, product, partner_id, context=None):
        for supinfo in product.seller_ids:
            if supinfo.name.id == partner_id:
                return {'code': supinfo.product_code or product.default_code, 'name': supinfo.product_name or product.name, 'variants': ''}
        res = {'code': product.default_code, 'name': product.name, 'variants': product.variants}
        return res

    def _product_code(self, cr, uid, ids, name, arg, context=None):
        res = {}
        if context is None:
            context = {}
        for p in self.browse(cr, uid, ids, context=context):
            res[p.id] = self._get_partner_code_name(cr, uid, [], p, context.get('partner_id', None), context=context)['code']
        return res

    def _product_partner_ref(self, cr, uid, ids, name, arg, context=None):
        res = {}
        if context is None:
            context = {}
        for p in self.browse(cr, uid, ids, context=context):
            data = self._get_partner_code_name(cr, uid, [], p, context.get('partner_id', None), context=context)
            if not data['variants']:
                data['variants'] = p.variants
            if not data['code']:
                data['code'] = p.code
            if not data['name']:
                data['name'] = p.name
            res[p.id] = (data['code'] and ('[' + data['code'] + '] ') or '') + \
                    (data['name'] or '') + (data['variants'] and (' - ' + data['variants']) or '')
        return res


    def _get_main_product_supplier(self, cr, uid, product, context=None):
        """Determines the main (best) product supplier for ``product``,
        returning the corresponding ``supplierinfo`` record, or False
        if none were found. The default strategy is to select the
        supplier with the highest priority (i.e. smallest sequence).

        :param browse_record product: product to supply
        :rtype: product.supplierinfo browse_record or False
        """
        sellers = [(seller_info.sequence, seller_info)
                       for seller_info in product.seller_ids or []
                       if seller_info and isinstance(seller_info.sequence, (int, long))]
        return sellers and sellers[0][1] or False

    def _calc_seller(self, cr, uid, ids, fields, arg, context=None):
        result = {}
        for product in self.browse(cr, uid, ids, context=context):
            main_supplier = self._get_main_product_supplier(cr, uid, product, context=context)
            result[product.id] = {
                'seller_info_id': main_supplier and main_supplier.id or False,
                'seller_delay': main_supplier.delay if main_supplier else 1,
                'seller_qty': main_supplier and main_supplier.qty or 0.0,
                'seller_id': main_supplier and main_supplier.name.id or False
            }
        return result


    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, avoid_resize_medium=True)
        return result

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

    _defaults = {
        'active': lambda *a: 1,
        'price_extra': lambda *a: 0.0,
        'price_margin': lambda *a: 1.0,
        'color': 0,
    }

    _name = "product.product"
    _description = "Product"
    _table = "product_product"
    _inherits = {'product.template': 'product_tmpl_id'}
    _inherit = ['mail.thread']
    _order = 'default_code,name_template'
    _columns = {
        'qty_available': fields.function(_product_qty_available, type='float', string='Quantity On Hand'),
        'virtual_available': fields.function(_product_virtual_available, type='float', string='Quantity Available'),
        'incoming_qty': fields.function(_product_incoming_qty, type='float', string='Incoming'),
        'outgoing_qty': fields.function(_product_outgoing_qty, type='float', string='Outgoing'),
        'price': fields.function(_product_price, type='float', string='Price', digits_compute=dp.get_precision('Product Price')),
        'lst_price' : fields.function(_product_lst_price, type='float', string='Public Price', digits_compute=dp.get_precision('Product Price')),
        'code': fields.function(_product_code, type='char', string='Internal Reference'),
        'partner_ref' : fields.function(_product_partner_ref, type='char', string='Customer ref'),
        'default_code' : fields.char('Internal Reference', size=64, select=True),
        'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the product without removing it."),
        'variants': fields.char('Variants', size=64),
        'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete="cascade", select=True),
        'ean13': fields.char('EAN13 Barcode', size=13, help="International Article Number used for product identification."),
        'packaging' : fields.one2many('product.packaging', 'product_id', 'Logistical Units', help="Gives the different ways to package the same product. This has no impact on the picking order and is mainly used if you use the EDI module."),
        'price_extra': fields.float('Variant Price Extra', digits_compute=dp.get_precision('Product Price')),
        'price_margin': fields.float('Variant Price Margin', digits_compute=dp.get_precision('Product Price')),
        'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),
        'name_template': fields.related('product_tmpl_id', 'name', string="Template Name", type='char', size=128, store=True, select=True),
        'color': fields.integer('Color Index'),
        # image: all image fields are base64 encoded and PIL-supported
        'image': fields.binary("Image",
            help="This field holds the image used as image for the product, limited to 1024x1024px."),
        'image_medium': fields.function(_get_image, fnct_inv=_set_image,
            string="Medium-sized image", type="binary", multi="_get_image",
            store={
                'product.product': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
            },
            help="Medium-sized image of the product. It is automatically "\
                 "resized as a 128x128px image, with aspect ratio preserved, "\
                 "only when the image exceeds one of those sizes. Use this field in form views or some kanban views."),
        'image_small': fields.function(_get_image, fnct_inv=_set_image,
            string="Small-sized image", type="binary", multi="_get_image",
            store={
                'product.product': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
            },
            help="Small-sized image of the product. It is automatically "\
                 "resized as a 64x64px image, with aspect ratio preserved. "\
                 "Use this field anywhere a small image is required."),
        'seller_info_id': fields.function(_calc_seller, type='many2one', relation="product.supplierinfo", string="Supplier Info", multi="seller_info"),
        'seller_delay': fields.function(_calc_seller, type='integer', string='Supplier Lead Time', multi="seller_info", help="This is the average delay in days between the purchase order confirmation and the reception of goods for this product and for the default supplier. It is used by the scheduler to order requests based on reordering delays."),
        'seller_qty': fields.function(_calc_seller, type='float', string='Supplier Quantity', multi="seller_info", help="This is minimum quantity to purchase from Main Supplier."),
        'seller_id': fields.function(_calc_seller, type='many2one', relation="res.partner", string='Main Supplier', help="Main Supplier who has highest priority in Supplier List.", multi="seller_info"),
    }
    def unlink(self, cr, uid, ids, context=None):
        unlink_ids = []
        unlink_product_tmpl_ids = []
        for product in self.browse(cr, uid, ids, context=context):
            tmpl_id = product.product_tmpl_id.id
            # Check if the product is last product of this template
            other_product_ids = self.search(cr, uid, [('product_tmpl_id', '=', tmpl_id), ('id', '!=', product.id)], context=context)
            if not other_product_ids:
                unlink_product_tmpl_ids.append(tmpl_id)
            unlink_ids.append(product.id)
        res = super(product_product, self).unlink(cr, uid, unlink_ids, context=context)
        # delete templates after calling super, as deleting template could lead to deleting
        # products due to ondelete='cascade'
        self.pool.get('product.template').unlink(cr, uid, unlink_product_tmpl_ids, context=context)
        return res

    def onchange_uom(self, cursor, user, ids, uom_id, uom_po_id):
        if uom_id and uom_po_id:
            uom_obj = self.pool.get('product.uom')
            uom = uom_obj.browse(cursor, user, [uom_id])[0]
            uom_po = uom_obj.browse(cursor, user, [uom_po_id])[0]
            if uom.category_id.id != uom_po.category_id.id:
                return {'value': {'uom_po_id': uom_id}}
        return False

    def _check_ean_key(self, cr, uid, ids, context=None):
        for product in self.read(cr, uid, ids, ['ean13'], context=context):
            res = check_ean(product['ean13'])
        return res


    _constraints = [(_check_ean_key, 'You provided an invalid "EAN13 Barcode" reference. You may use the "Internal Reference" field instead.', ['ean13'])]

    def on_order(self, cr, uid, ids, orderline, quantity):
        pass

    def name_get(self, cr, user, ids, context=None):
        if context is None:
            context = {}
        if isinstance(ids, (int, long)):
            ids = [ids]
        if not len(ids):
            return []
        def _name_get(d):
            name = d.get('name', '')
            code = d.get('default_code', False)
            if code:
                name = '[%s] %s' % (code, name)
            if d.get('variants'):
                name = name + ' - %s' % (d['variants'],)
            return (d['id'], name)

        partner_id = context.get('partner_id', False)

        result = []
        for product in self.browse(cr, user, ids, context=context):
            sellers = filter(lambda x: x.name.id == partner_id, product.seller_ids)
            if sellers:
                for s in sellers:
                    mydict = {
                              'id': product.id,
                              'name': s.product_name or product.name,
                              'default_code': s.product_code or product.default_code,
                              'variants': product.variants
                              }
                    result.append(_name_get(mydict))
            else:
                mydict = {
                          'id': product.id,
                          'name': product.name,
                          'default_code': product.default_code,
                          'variants': product.variants
                          }
                result.append(_name_get(mydict))
        return result

    def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100):
        
        if not args:
            args = []
        if name:
            ids = self.search(cr, user, [('default_code', '=', name)] + args, limit=limit, context=context)
            if not ids:
                ids = self.search(cr, user, [('ean13', '=', name)] + args, limit=limit, context=context)
            if not ids:
                # Do not merge the 2 next lines into one single search, SQL search performance would be abysmal
                # on a database with thousands of matching products, due to the huge merge+unique needed for the
                # OR operator (and given the fact that the 'name' lookup results come from the ir.translation table
                # Performing a quick memory merge of ids in Python will give much better performance
                ids = set()
                ids.update(self.search(cr, user, args + [('default_code', operator, name)], limit=limit, context=context))
                if not limit or len(ids) < limit:
                    # we may underrun the limit because of dupes in the results, that's fine
                    ids.update(self.search(cr, user, args + [('name', operator, name)], limit=(limit and (limit - len(ids)) or False) , context=context))
                ids = list(ids)
            if not ids:
                ptrn = re.compile('(\[(.*?)\])')
                res = ptrn.search(name)
                if res:
                    ids = self.search(cr, user, [('default_code', '=', res.group(2))] + args, limit=limit, context=context)
        else:
            ids = self.search(cr, user, args, limit=limit, context=context)
        result = self.name_get(cr, user, ids, context=context)
        return result

    #
    # Could be overrided for variants matrices prices
    #
    def price_get(self, cr, uid, ids, ptype='list_price', context=None):
        if context is None:
            context = {}

        if 'currency_id' in context:
            pricetype_obj = self.pool.get('product.price.type')
            price_type_id = pricetype_obj.search(cr, uid, [('field', '=', ptype)])[0]
            price_type_currency_id = pricetype_obj.browse(cr, uid, price_type_id).currency_id.id

        res = {}
        product_uom_obj = self.pool.get('product.uom')
        for product in self.browse(cr, uid, ids, context=context):
            res[product.id] = product[ptype] or 0.0
            if ptype == 'list_price':
                res[product.id] = (res[product.id] * (product.price_margin or 1.0)) + \
                        product.price_extra
            if 'uom' in context:
                uom = product.uom_id or product.uos_id
                res[product.id] = product_uom_obj._compute_price(cr, uid,
                        uom.id, res[product.id], context['uom'])
            # Convert from price_type currency to asked one
            if 'currency_id' in context:
                # Take the price_type currency from the product field
                # This is right cause a field cannot be in more than one currency
                res[product.id] = self.pool.get('res.currency').compute(cr, uid, price_type_currency_id,
                    context['currency_id'], res[product.id], context=context)

        return res

    def copy(self, cr, uid, id, default=None, context=None):
        if context is None:
            context = {}

        if not default:
            default = {}

        # Craft our own `<name> (copy)` in en_US (self.copy_translation()
        # will do the other languages).
        context_wo_lang = context.copy()
        context_wo_lang.pop('lang', None)
        product = self.read(cr, uid, id, ['name'], context=context_wo_lang)
        default = default.copy()
        default.update(name=_("%s (copy)") % (product['name']))

        if context.get('variant', False):
            fields = ['product_tmpl_id', 'active', 'variants', 'default_code',
                    'price_margin', 'price_extra']
            data = self.read(cr, uid, id, fields=fields, context=context)
            for f in fields:
                if f in default:
                    data[f] = default[f]
            data['product_tmpl_id'] = data.get('product_tmpl_id', False) \
                    and data['product_tmpl_id'][0]
            del data['id']
            return self.create(cr, uid, data)
        else:
            return super(product_product, self).copy(cr, uid, id, default=default,
                    context=context)

    def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
        print args
        if context is None:
            context = {}
        if context and context.get('search_default_categ_id', False):
            args.append((('categ_id', 'child_of', context['search_default_categ_id'])))
        return super(product_product, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=False)