def _update_models(self, cr, models={}):
     if not models:
         checklist_ids = self.search(cr, 1, [])
         models = dict([(checklist['model_id'][0], {'checklist_id': checklist['id'], 'active_field': checklist['active_field']})
                        for checklist in self.read(cr, 1, checklist_ids, ['model_id', 'active_field'])])
     for model in self.pool.get('ir.model').read(cr, 1, models.keys(), ['model']):
         if self.pool.get(model['model']):
             model_columns = self.pool.get(model['model'])._columns
             checklist_id = models[model['id']] and models[model['id']].get('checklist_id', False)
             if checklist_id:
                 model_columns.update({
                     'checklist_task_instance_ids': fields.function(self._get_checklist_task_instances, type='one2many',
                                                                    relation='checklist.task.instance', string='Checklist Task Instances',
                                                                    store=False),
                     'total_progress_rate': fields.float('Progress Rate', digits=(16, 2)),
                 })
                 columns_to_add = {'total_progress_rate': 'NUMERIC(16,2)'}
                 if models[model['id']].get('active_field', False):
                     if 'active' not in model_columns or model_columns['active']._type != 'boolean':
                         model_columns.update({'active': fields.boolean('Active')})
                     model_columns.update({'total_progress_rate_mandatory': fields.float('Mandatory Progress Rate', digits=(16, 2))})
                     columns_to_add.update({'active': 'BOOLEAN', 'total_progress_rate_mandatory': 'NUMERIC(16,2)'})
                 for column in columns_to_add:
                     cr.execute("""SELECT c.relname FROM pg_class c, pg_attribute a
                                   WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid""", (model['model'].replace('.', '_'), column))
                     if not cr.rowcount:
                         cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (model['model'].replace('.', '_'), column, columns_to_add[column]))
                         cr.commit()
             else:
                 if 'checklist_task_instance_ids' in model_columns:
                     del model_columns['checklist_task_instance_ids']
                 if 'total_progress_rate' in model_columns:
                     del model_columns['total_progress_rate']
     return self._update_checklists_cache(cr)
Example #2
0
    def __init__(self, pool, cr):
        """ Dynamically add columns."""

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

        for counter in range(0, MAX_PARAMS):
            field_name = PARAM_XXX_STRING_VALUE % counter
            self._columns[field_name] = fields.char('String Value', size=64)
            field_name = PARAM_XXX_BOOLEAN_VALUE % counter
            self._columns[field_name] = fields.boolean('Boolean Value')
            field_name = PARAM_XXX_INTEGER_VALUE % counter
            self._columns[field_name] = fields.integer('Integer Value')
            field_name = PARAM_XXX_NUMBER_VALUE % counter
            self._columns[field_name] = fields.float('Number Value')
            field_name = PARAM_XXX_DATE_VALUE % counter
            self._columns[field_name] = fields.date('Date Value')
            field_name = PARAM_XXX_TIME_VALUE % counter
            self._columns[field_name] = fields.datetime('Time Value')

        self.paramfile = False
Example #3
0
    def __init__(self, pool, cr):
        """ Dynamically add columns."""

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

        for counter in range(0, MAX_PARAMS):
            field_name = PARAM_XXX_STRING_VALUE % counter
            self._columns[field_name] = fields.char('String Value', size=64)
            field_name = PARAM_XXX_BOOLEAN_VALUE % counter
            self._columns[field_name] = fields.boolean('Boolean Value')
            field_name = PARAM_XXX_INTEGER_VALUE % counter
            self._columns[field_name] = fields.integer('Integer Value')
            field_name = PARAM_XXX_NUMBER_VALUE % counter
            self._columns[field_name] = fields.float('Number Value')
            field_name = PARAM_XXX_DATE_VALUE % counter
            self._columns[field_name] = fields.date('Date Value')
            field_name = PARAM_XXX_TIME_VALUE % counter
            self._columns[field_name] = fields.datetime('Time Value')
            field_name = PARAM_XXX_2M_VALUE % counter
            self._columns[field_name] = fields.function(self._multi_select_values.im_func,
                                                        arg={"entry_num": counter},
                                                        fnct_inv=self._multi_select_values_store.im_func,
                                                        fnct_inv_arg={"entry_num": counter},
                                                        method=False, type='many2many', relation='ir.actions.report.multivalues.promptwizard', string='Multi-Select')
Example #4
0
        """Get the picking ids of the given Stock Packages."""
        result = {}
        for line in self.pool.get('stock.packages').browse(cr, uid, ids, context=None):
            result[line.pick_id.id] = True
        return result.keys()

    def _get_company_code(self, cr, user, context=None):
<<<<<<< HEAD
        return super(stock_picking, self)._get_company_code(cr, user, context=context)
=======
        return []
>>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d
    
    _columns = {
        'logis_company': fields.many2one('logistic.company', 'Logistics Company', help='Name of the Logistics company providing the shipper services.'),
        'freight': fields.boolean('Shipment', help='Indicates if the shipment is a freight shipment.'),
        'sat_delivery': fields.boolean('Saturday Delivery', help='Indicates is it is appropriate to send delivery on Saturday.'),
        'package_type': fields.selection([
            ('01', 'Letter'),
            ('02', 'Customer Supplied Package'),
            ('03', 'Tube'),
            ('04', 'PAK'),
            ('21', 'ExpressBox'),
            ('24', '25KG Box'),
            ('25', '10KG Box'),
            ('30', 'Pallet'),
            ('2a', 'Small Express Box'),
            ('2b', 'Medium Express Box'),
            ('2c', 'Large Express Box')
            ], 'Package Type', help='Indicates the type of package'),
        'bill_shipping': fields.selection([
Example #5
0
class Product(osv.osv):
    def fields_view_get(self,
                        cr,
                        user,
                        view_id=None,
                        view_type='form',
                        context=None,
                        toolbar=False,
                        submenu=False):
        model_obj = self.pool.get('ir.model.data')
        if context is None:
            context = {}

        if ('product' in context) and (context['product']
                                       == 'membership_product'):
            model_data_ids_form = model_obj.search(
                cr,
                user,
                [('model', '=', 'ir.ui.view'),
                 ('name', 'in',
                  ['membership_products_form', 'membership_products_tree'])],
                context=context)
            resource_id_form = model_obj.read(cr,
                                              user,
                                              model_data_ids_form,
                                              fields=['res_id', 'name'],
                                              context=context)
            dict_model = {}
            for i in resource_id_form:
                dict_model[i['name']] = i['res_id']
            if view_type == 'form':
                view_id = dict_model['membership_products_form']
            else:
                view_id = dict_model['membership_products_tree']
        return super(Product, self).fields_view_get(cr,
                                                    user,
                                                    view_id,
                                                    view_type,
                                                    context=context,
                                                    toolbar=toolbar,
                                                    submenu=submenu)

    '''Product'''
    _inherit = 'product.template'
    _columns = {
        'membership':
        fields.boolean(
            'Membership',
            help='Check if the product is eligible for membership.'),
        'membership_date_from':
        fields.date('Membership Start Date',
                    help='Date from which membership becomes active.'),
        'membership_date_to':
        fields.date('Membership End Date',
                    help='Date until which membership remains active.'),
    }

    _sql_constraints = [
        ('membership_date_greater',
         'check(membership_date_to >= membership_date_from)',
         'Error ! Ending Date cannot be set before Beginning Date.')
    ]
    _defaults = {
        'membership': False,
    }
Example #6
0
    def _save_file(self, path, b64_file):
        """Save a file encoded in base 64"""
        self._check_filestore(path)
        with open(path, 'w') as ofile:
            ofile.write(base64.b64decode(b64_file))
        return True

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

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

Example #7
0
            save_cron.update({'interval_type':vals.get('interval_type')})
        if save_cron:
            self.pool.get('currency.rate.update').save_cron(
                cr,
                uid,
                save_cron
            )

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



    _inherit = "res.company"
    _columns = {
        ### activate the currency update
        'auto_currency_up': fields.boolean('Automatical update of the currency this company'),
        'services_to_use' : fields.one2many(
                                            'currency.rate.update.service',
                                            'company_id',
                                            'Currency update services'
                                            ),
        ###predifine cron frequence
        'interval_type': fields.selection(
                                                [
                                                    ('days','Day(s)'),
                                                    ('weeks', 'Week(s)'),
                                                    ('months', 'Month(s)')
                                                ],
                                                'Currency update frequence',
                                                help="""changing this value will
                                                 also affect other compagnies"""
Example #8
0
  - The 'Invoice On Order After Delivery' choice will generate the draft invoice based on sales order after all picking lists have been finished.
  - The 'Invoice From The Picking' choice is used to create an invoice during the picking process."""),
        'state': fields.selection([
            ('draft', 'Draft Quotation'),
            ('sent', 'Quotation Sent'),
            ('cancel', 'Cancelled'),
            ('waiting_date', 'Waiting Schedule'),
            ('progress', 'Sales Order'),
            ('cc_auth', 'Draft Authorized'),
            ('manual', 'Sale to Invoice'),
            ('invoice_except', 'Invoice Exception'),
            ('shipping_except', 'Shipping Exception'),
            ('done', 'Done')
            ], 'Status', readonly=True, track_visibility='onchange',
            help="Gives the status of the quotation or sales order. \nThe exception status is automatically set when a cancel operation occurs in the processing of a document linked to the sales order. \nThe 'Waiting Schedule' status is set when the invoice is confirmed but waiting for the scheduler to run on the order date.", select=True),
        'cc_pre_auth':fields.boolean('Creditcard Pre-authorised'),
        'rel_account_voucher_id':fields.many2one('account.voucher', 'Related Payment'),
        'invoiced': fields.function(_invoiced, method=True, string='Paid',
        type='boolean', help="It indicates that an invoice has been paid.",
        store={
             'account.invoice'  : (_get_invoice, ['state'], 20),
             'sale.order'       : (lambda self, cr, uid, ids, c={}: ids, ['state'], 20),
             'account.voucher'  : (_get_voucher, ['state'], 20),
         }),
        'cc_ship_refund' : fields.boolean('Ship Refunded', readonly=True),
    }

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None:
            default = {}
        if context is None:
Example #9
0
        'scheduler':fields.many2one('ir.cron', 'Scheduler',help="Scheduler that will execute the cron task"),
        'search_filter':  fields.char('Search Filter', size=256),
        'filename': fields.char('Filename', size=128, help="Filename will be used to generate the output file name or to read the incoming file. It is possible to use variables (check in sequence for syntax)", require=True),
        'folder_path': fields.char('Folder Path', size=128, help="folder that containt the incomming or the outgoing file"),
        'archive_folder_path': fields.char('Archive Folder Path', size=128, help="if a path is set when a file is imported the file will be automatically moved to this folder"),
        'encoding': fields.selection(_get_encoding, 'Encoding', require=True),
        'field_ids': fields.one2many('file.fields', 'file_id', 'Fields'),
        'action_before_all': fields.text('Action Before All', help="This python code will executed after the import/export"),
        'action_after_all': fields.text('Action After All', help="This python code will executed after the import/export"),
        'action_before_each': fields.text('Action Before Each', help="This python code will executed after each element of the import/export"),
        'action_after_each': fields.text('Action After Each', help="This python code will executed after each element of the import/export"),
        'check_if_import': fields.text('Check If Import', help="This python code will be executed before each element of the import"),
        'delimiter':fields.char('Fields delimiter', size=64, help="Delimiter used in the CSV file"),
        'lang': fields.many2one('res.lang', 'Language'),
        'import_default_fields':fields.one2many('file.default.import.values', 'file_id', 'Default Field'),
        'do_not_update':fields.boolean('Do Not Update'),
        'pre_processing': fields.text('Pre-Processing', help="This python code will be executed before merge of elements of the import"),
        'mapping_template_id':fields.many2one('external.mapping.template', 'External Mapping Template', require="True"),
        'notes': fields.text('Notes'),
        'related_mapping_ids': fields.function(_get_related_mapping_ids, type="many2many", relation="external.mapping", string='Related Mappings'),
        'synchronize_from': fields.selection([('referential', 'Referential'), ('pop_up', 'Pop Up')], string='Synchronize From'),
        'linked_task': fields.many2one('file.exchange', 'Linked Task'),
    }

    def get_absolute_id(self, cr, uid, id, context=None):
        if isinstance(id,list):
            id = id[0]
        file_exchange = self.browse(cr, uid, id, context=context)
        file_exchange_id = file_exchange.get_external_id(context=context)[file_exchange.id]
        if not file_exchange_id:
            file_exchange_id = file_exchange.name.replace(' ','_').replace('.','_')
Example #10
0
class social_programs_program_delivery(osv.osv, format_address):
    _description = "Entrega Programas sociales"
    _name = 'social.programs.program.delivery'

    def action_delivery_product(self, cr, uid, ids, context=None):
        """
            Muestra una ventana con la informacion del documento a entregar
        """

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

        mod_obj = self.pool.get('ir.model.data')
        res = mod_obj.get_object_reference(
            cr, uid, 'social_programs',
            'view_social_programs_program_delivery_form')
        res_id = res and res[1] or False

        #~ Redirecciona al formulario de Entrega
        return {
            'name': "Entrega",
            'view_type': 'form',
            'view_mode': 'form',
            'view_id': [res_id],
            'res_model': 'social.programs.program.delivery',  # object name
            'type': 'ir.actions.act_window',
            'nodestroy': True,
            'target': 'new',
            'res_id': ids[0],  # id of the object to which to redirected
        }

    def action_delivery(self, cr, uid, ids, context=None):
        """
            Pone el documento como entregado
        """
        date = fields.date.context_today(self, cr, uid, context=context)
        self.write(cr,
                   uid,
                   ids, {
                       'delivery': True,
                       'date': date
                   },
                   context=context)
        print "*************** cambio de estado **************** "

        #~ Cierra la ventana
        return {'type': 'ir.actions.act_window_close'}

    def action_delivery_and_print(self, cr, uid, ids, context=None):
        """
            Entrega el documento e imprime el reporte
        """
        self.action_delivery(cr, uid, ids, context=context)
        res = self.action_print_report(cr, uid, ids, context=context)
        return res

    def action_print_report(self, cr, uid, ids, context=None):
        datas = {}
        if context is None:
            context = {}
        print "************** active_ids ************* ", context.get(
            'active_ids', [])

        data = self.read(cr, uid, ids)[0]
        datas = {
            'ids': ids,
            'model': 'social.programs.program.delivery',
            'form': data
        }
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'report.social.programs.program.delivery.webkit',
            'datas': datas,
        }

    def onchange_delivery(self, cr, uid, ids, delivery, context=None):
        """
            Cierra la ventana si cambia el estado a entregado
        """
        if delivery == True:
            return {'type': 'ir.actions.act_window_close'}
        return True

    _columns = {
        'program_id':
        fields.many2one('social.programs.program', 'Programa', readonly=True),
        'partner_id':
        fields.many2one('res.partner', 'Beneficiario', readonly=True),
        'product_id':
        fields.many2one('product.product', 'Producto', readonly=True),
        'qty':
        fields.float('Cantidad a entregar', readonly=True),
        'date':
        fields.date('Entregado', readonly=True),
        'delivery':
        fields.boolean('Entregado', readonly=True),
        # Campos relacionados con el beneficiario
        'name':
        fields.related('partner_id',
                       'name',
                       type="char",
                       string="Nombre",
                       readonly=True),
        'curp':
        fields.related('partner_id',
                       'curp',
                       type="char",
                       string="curp",
                       readonly=True),
        'image':
        fields.related('partner_id',
                       'image',
                       type="binary",
                       string="Image",
                       readonly=True),
        'image_medium':
        fields.related('partner_id',
                       'image_medium',
                       type="binary",
                       string="Image medium",
                       readonly=True),
        'category_id':
        fields.many2many("res.partner.category",
                         'partner_id',
                         'category_id',
                         string="Etiquetas",
                         readonly=True),
        'street':
        fields.related('partner_id',
                       'street',
                       type="char",
                       string="Calle",
                       readonly=True),
        'settlement_id':
        fields.related('partner_id',
                       'settlement_id',
                       type='many2one',
                       relation='social.programs.res.settlement',
                       string='Colonia',
                       readonly=True),
        'city_id':
        fields.related('partner_id',
                       'city_id',
                       type='many2one',
                       relation='social.programs.res.city',
                       string='Ciudad',
                       readonly=True),
        'state_id':
        fields.related('partner_id',
                       'state_id',
                       type='many2one',
                       relation='res.country.state',
                       string='Estado',
                       readonly=True),
        'zip':
        fields.related('partner_id',
                       'zip',
                       type="char",
                       string="C.P.",
                       readonly=True),
        'sector_id':
        fields.related('partner_id',
                       'sector_id',
                       type='many2one',
                       relation='social.programs.res.sector',
                       string='Sector',
                       readonly=True),
        'area_id':
        fields.related('partner_id',
                       'area_id',
                       type='many2one',
                       relation='social.programs.res.area',
                       string='Area',
                       readonly=True),
        'country_id':
        fields.related('partner_id',
                       'country_id',
                       type='many2one',
                       relation='res.country',
                       string='Estado',
                       readonly=True),
        'phone':
        fields.related('partner_id',
                       'phone',
                       type="char",
                       string="Telefono",
                       readonly=True),
        'mobile':
        fields.related('partner_id',
                       'mobile',
                       type="char",
                       string="Celular",
                       readonly=True),
        'email':
        fields.related('partner_id',
                       'email',
                       type="char",
                       string="Correo",
                       readonly=True),
    }

    _defaults = {'delivery': False}

    _order = 'delivery,program_id,partner_id,product_id,qty'
class AccountStatementProfil(Model):
    _inherit = "account.statement.profile"

    def get_import_type_selection(self, cr, uid, context=None):
        """This is the method to be inherited for adding the parser"""
        return [('generic_csvxls_so', 'Generic .csv/.xls based on SO Name')]

    def _get_import_type_selection(self, cr, uid, context=None):
        return self.get_import_type_selection(cr, uid, context=context)

    _columns = {
        'launch_import_completion': fields.boolean(
            "Launch completion after import",
            help="Tic that box to automatically launch the completion "
                 "on each imported file using this profile."),
        'last_import_date': fields.datetime("Last Import Date"),
        #  we remove deprecated as it floods logs in standard/warning level sob...
        'rec_log': fields.text('log', readonly=True),  # Deprecated
        'import_type': fields.selection(
            _get_import_type_selection,
            'Type of import',
            required=True,
            help="Choose here the method by which you want to import bank"
                 "statement for this profile."),
    }

    _defaults = {
                'import_type': 'generic_csvxls_so'
            }

    def _write_extra_statement_lines(
            self, cr, uid, parser, result_row_list, profile, statement_id, context):
        """Insert extra lines after the main statement lines.

        After the main statement lines have been created, you can override this method to create
        extra statement lines.

            :param:    browse_record of the current parser
            :param:    result_row_list: [{'key':value}]
            :param:    profile: browserecord of account.statement.profile
            :param:    statement_id: int/long of the current importing statement ID
            :param:    context: global context
        """
        pass

    def write_logs_after_import(self, cr, uid, ids, statement_id, num_lines, context):
        """
        Write the log in the logger

        :param int/long statement_id: ID of the concerned account.bank.statement
        :param int/long num_lines: Number of line that have been parsed
        :return: True
        """
        self.message_post(cr,
                          uid,
                          ids,
                          body=_('Statement ID %s have been imported with %s lines.') %
                                (statement_id, num_lines),
                          context=context)
        return True

    #Deprecated remove on V8
    def prepare_statetement_lines_vals(self, *args, **kwargs):
        return self.prepare_statement_lines_vals(*args, **kwargs)

    def prepare_statement_lines_vals(
            self, cr, uid, parser_vals,
            statement_id, context):
        """
        Hook to build the values of a line from the parser returned values. At
        least it fullfill the statement_id. Overide it to add your
        own completion if needed.

        :param dict of vals from parser for account.bank.statement.line (called by
                parser.get_st_line_vals)
        :param int/long statement_id: ID of the concerned account.bank.statement
        :return: dict of vals that will be passed to create method of statement line.
        """
        statement_line_obj = self.pool['account.bank.statement.line']
        values = parser_vals
        values['statement_id'] = statement_id
        date = values.get('date')
        period_memoizer = context.get('period_memoizer')
        if not period_memoizer:
            period_memoizer = {}
            context['period_memoizer'] = period_memoizer
        if period_memoizer.get(date):
            values['period_id'] = period_memoizer[date]
        else:
            # This is awfully slow...
            periods = self.pool.get('account.period').find(cr, uid,
                                                           dt=values.get('date'),
                                                           context=context)
            values['period_id'] = periods[0]
            period_memoizer[date] = periods[0]
        values = statement_line_obj._add_missing_default_values(cr, uid, values, context)
        return values

    def prepare_statement_vals(self, cr, uid, profile_id, result_row_list, parser, context):
        """
        Hook to build the values of the statement from the parser and
        the profile.
        """
        vals = {'profile_id': profile_id}
        vals.update(parser.get_st_vals())
        return vals

    def multi_statement_import(self, cr, uid, ids, profile_id, file_stream,
                               ftype="csv", context=None):
        """
        Create multiple bank statements from values given by the parser for the
         givenprofile.

        :param int/long profile_id: ID of the profile used to import the file
        :param filebuffer file_stream: binary of the providen file
        :param char: ftype represent the file exstension (csv by default)
        :return: list: list of ids of the created account.bank.statemênt
        """
        prof_obj = self.pool['account.statement.profile']
        if not profile_id:
            raise osv.except_osv(_("No Profile!"),
             _("You must provide a valid profile to import a bank statement!"))
        prof = prof_obj.browse(cr, uid, profile_id, context=context)

        parser = new_bank_statement_parser(prof.import_type, ftype=ftype)
        res = []
        for result_row_list in parser.parse(file_stream):
            statement_id = self._statement_import(cr, uid, ids, prof, parser,
                                    file_stream, ftype=ftype, context=context)
            res.append(statement_id)
        return res

    def _statement_import(self, cr, uid, ids, prof, parser, file_stream, ftype="csv", context=None):
        """
        Create a bank statement with the given profile and parser. It will fullfill the bank statement
        with the values of the file providen, but will not complete data (like finding the partner, or
        the right account). This will be done in a second step with the completion rules.

        :param prof : The profile used to import the file
        :param parser: the parser
        :param filebuffer file_stream: binary of the providen file
        :param char: ftype represent the file exstension (csv by default)
        :return: ID of the created account.bank.statemênt
        """
        statement_obj = self.pool.get('account.bank.statement')
        statement_line_obj = self.pool.get('account.bank.statement.line')
        attachment_obj = self.pool.get('ir.attachment')

        result_row_list = parser.result_row_list
        # Check all key are present in account.bank.statement.line!!
        if not result_row_list:
            raise osv.except_osv(_("Nothing to import"),
                                 _("The file is empty"))
        parsed_cols = parser.get_st_line_vals(result_row_list[0]).keys()
        for col in parsed_cols:
            if col not in statement_line_obj._columns:
                raise osv.except_osv(_("Missing column!"),
                                     _("Column %s you try to import is not "
                                       "present in the bank statement line!") % col)

        statement_vals = self.prepare_statement_vals(cr, uid, prof.id, result_row_list, parser, context)
        statement_id = statement_obj.create(cr, uid,
                                            statement_vals,
                                            context=context)

        try:
            # Record every line in the bank statement
            statement_store = []
            for line in result_row_list:
                parser_vals = parser.get_st_line_vals(line)
                values = self.prepare_statement_lines_vals(
                    cr, uid, parser_vals, statement_id,
                    context)
                statement_store.append(values)
            # Hack to bypass ORM poor perfomance. Sob...
            statement_line_obj._insert_lines(cr, uid, statement_store, context=context)

            self._write_extra_statement_lines(
                cr, uid, parser, result_row_list, prof, statement_id, context)
            # Trigger store field computation if someone has better idea
            start_bal = statement_obj.read(
                cr, uid, statement_id, ['balance_start'], context=context)
            start_bal = start_bal['balance_start']
            statement_obj.write(cr, uid, [statement_id], {'balance_start': start_bal})

            attachment_data = {
                'name': 'statement file',
                'datas': file_stream,
                'datas_fname': "%s.%s" % (datetime.datetime.now().date(), ftype),
                'res_model': 'account.bank.statement',
                'res_id': statement_id,
            }
            attachment_obj.create(cr, uid, attachment_data, context=context)

            # If user ask to launch completion at end of import, do it!
            if prof.launch_import_completion:
                statement_obj.button_auto_completion(cr, uid, [statement_id], context)

            # Write the needed log infos on profile
            self.write_logs_after_import(cr, uid, prof.id,
                                         statement_id,
                                         len(result_row_list),
                                         context)

        except Exception:
            error_type, error_value, trbk = sys.exc_info()
            st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value)
            st += ''.join(traceback.format_tb(trbk, 30))
            #TODO we should catch correctly the exception with a python
            #Exception and only re-catch some special exception.
            #For now we avoid re-catching error in debug mode
            if config['debug_mode']:
                raise
            raise osv.except_osv(_("Statement import error"),
                                 _("The statement cannot be created: %s") % st)
        return statement_id
Example #12
0
class social_programs_category(osv.osv):
    def name_get(self, cr, uid, ids, context=None):
        """Return the categories' display name, including their direct
           parent by default.

        :param dict context: the ``partner_category_display`` key can be
                             used to select the short version of the
                             category name (without the direct parent),
                             when set to ``'short'``. The default is
                             the long version."""
        if context is None:
            context = {}
        if context.get('partner_category_display') == 'short':
            return super(res_partner_category, self).name_get(cr,
                                                              uid,
                                                              ids,
                                                              context=context)
        if isinstance(ids, (int, long)):
            ids = [ids]
        reads = self.read(cr, uid, ids, ['name', 'parent_id'], context=context)
        res = []
        for record in reads:
            name = record['name']
            if record['parent_id']:
                name = record['parent_id'][1] + ' / ' + name
            res.append((record['id'], name))
        return res

    def name_search(self,
                    cr,
                    uid,
                    name,
                    args=None,
                    operator='ilike',
                    context=None,
                    limit=100):
        if not args:
            args = []
        if not context:
            context = {}
        if name:
            # Be sure name_search is symetric to name_get
            name = name.split(' / ')[-1]
            ids = self.search(cr,
                              uid, [('name', operator, name)] + args,
                              limit=limit,
                              context=context)
        else:
            ids = self.search(cr, uid, args, limit=limit, context=context)
        return self.name_get(cr, uid, ids, context)

    def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
        res = self.name_get(cr, uid, ids, context=context)
        return dict(res)

    _description = 'Programas Categorias'
    _name = 'social.programs.category'
    _columns = {
        'name':
        fields.char('Nombre de Categoria',
                    required=True,
                    size=64,
                    translate=True),
        'parent_id':
        fields.many2one('social.programs.category',
                        'Categoria Padre',
                        select=True,
                        ondelete='cascade'),
        'complete_name':
        fields.function(_name_get_fnc, type="char", string='Full Name'),
        'child_ids':
        fields.one2many('social.programs.category', 'parent_id',
                        'Child Categories'),
        'active':
        fields.boolean(
            'Active',
            help=
            "El campo activo permite ocultar la categoria sin tener que eliminarla."
        ),
        'parent_left':
        fields.integer('Left parent', select=True),
        'parent_right':
        fields.integer('Right parent', select=True),
        'program_ids':
        fields.many2many('social.programs.program',
                         id1='category_id',
                         id2='program_id',
                         string='Programas'),
    }
    _constraints = [
        (osv.osv._check_recursion,
         'Error ! You can not create recursive categories.', ['parent_id'])
    ]

    _defaults = {
        'active': 1,
    }

    _parent_store = True
    _parent_order = 'name'
    _order = 'parent_left'
Example #13
0
class social_programs_direction(osv.osv):
    _description = "Direcciones de programas sociales"
    _name = 'social.programs.direction'

    def onchange_state(self, cr, uid, ids, state_id, context=None):
        """
            Obtiene la informacion del pais en base a el estado seleccioando
        """
        if state_id:
            country_id = self.pool.get('res.country.state').browse(
                cr, uid, state_id, context).country_id.id
            return {'value': {'country_id': country_id}}
        return {}

    def onchange_settlement(self, cr, uid, ids, settlement_id, context=None):
        """
            Obtiene la informacion de ciudad, estado, pais, CP, etc... en base a la colonia seleccionada
        """
        if settlement_id:
            settlement = self.pool.get(
                'social.programs.res.settlement').browse(
                    cr, uid, settlement_id, context)
            if settlement.id:
                state = self.pool.get('res.country.state').browse(
                    cr, uid, settlement.city_id.state_id.id, context)
                return {
                    'value': {
                        'country_id': state.country_id.id,
                        'state_id': state.id,
                        'city_id': settlement.city_id.id,
                        'city': settlement.city_id.name,
                        'area_id': settlement.area_id.id,
                        'sector_id': settlement.sector_id.id,
                        'zip': settlement.zip
                    }
                }
        return {}

    _columns = {
        'name':
        fields.char('Nombre', size=128, required=True, select=True),
        # Datos de ubicacion
        'state_id':
        fields.many2one('res.country.state', 'Estado'),
        'country_id':
        fields.related('state_id',
                       'country_id',
                       type="many2one",
                       relation="res.country",
                       string="Country",
                       store=True),
        'city_id':
        fields.many2one("social.programs.res.city", 'Ciudad'),
        'settlement_id':
        fields.many2one('social.programs.res.settlement', 'Colonia'),
        'area_id':
        fields.related('settlement_id',
                       'area_id',
                       type="many2one",
                       relation="social.programs.res.area",
                       string="Area",
                       readonly=True),
        'sector_id':
        fields.related('settlement_id',
                       'sector_id',
                       type="many2one",
                       relation="social.programs.res.sector",
                       string="Sector",
                       readonly=True),
        'street':
        fields.char('Calle', size=128),
        'zip':
        fields.char('C.P.', change_default=True, size=24),
        'email':
        fields.char('Email', size=240),
        'phone':
        fields.char('Phone', size=64),
        'fax':
        fields.char('Fax', size=64),
        'mobile':
        fields.char('Mobile', size=64),
        # Datos complemento
        'user_id':
        fields.many2one('res.users',
                        'Director',
                        help='Encargado de la direccion.'),
        'comment':
        fields.text('Notas'),
        'active':
        fields.boolean('Active'),
    }
    _order = 'name'
Example #14
0
class address_address(orm.Model):

    _name = 'address.address'
    _inherit = ['mozaik.abstract.model']
    _description = 'Address'

    # private methods

    def _get_technical_name(self, cr, uid, values, context=None):
        """
        This method produces a technical name with the content of values.
        :type values: dictionary
        :param values: used to create a technical address name
            ``country_id``
            ``address_local_zip``
            ``zip_man``
            ``town_man``
            ``address_local_street_id``
            ``street_man``
            ``number``
            ``box``
        :rparam: formated values of ``values`` join wit a `#`.
                0 if value is null
        """
        technical_value = []
        for field in values.keys():
            value = values[field] or u'0'
            technical_value.append(format_value(value))
        return '#'.join(technical_value)

    def _get_linked_coordinates(self, cr, uid, ids, context=None):
        return self.pool['postal.coordinate'].search(
            cr, uid, [('address_id', 'in', ids)], context=context)

    def _get_integral_address(self, cr, uid, ids, name, args, context=None):
        result = {
            i: {key: False
                for key in ['name', 'technical_name']}
            for i in ids
        }
        adrs_recs = self.browse(cr, uid, ids, context=context)
        for adrs in adrs_recs:
            elts = [
                adrs.street or False,
                adrs.sequence and '[%s]' % adrs.sequence or False,
                adrs.street and '-' or adrs.sequence and '-' or False,
                (adrs.country_code == 'BE') and adrs.zip or False,
                adrs.city or False,
                (adrs.country_code != 'BE') and '-' or False,
                (adrs.country_code != 'BE') and adrs.country_id.name or False,
            ]
            adr = ' '.join([el for el in elts if el])

            values = KEY_FIELDS.copy()
            for field in KEY_FIELDS.keys():
                to_evaluate = field if not KEY_FIELDS[field] else '%s.%s' % (
                    field, KEY_FIELDS[field])
                real_value = eval('adrs.%s' % to_evaluate)
                values[field] = real_value
            technical_name = self._get_technical_name(cr,
                                                      uid,
                                                      values,
                                                      context=context)

            result[adrs.id] = {
                'name': adr or False,
                'technical_name': technical_name or False,
            }
        return result

    def _get_street(self, cr, uid, ids, name, args, context=None):
        result = {i: False for i in ids}
        adrs_recs = self.browse(cr, uid, ids, context=context)
        for adrs in adrs_recs:
            number = adrs.number or '-'
            number = adrs.box and '%s/%s' % (number, adrs.box) or \
                adrs.number or False
            if adrs.address_local_street_id:
                street = adrs.select_alternative_address_local_street and \
                    adrs.address_local_street_id.local_street_alternative or \
                    adrs.address_local_street_id.local_street
            else:
                street = adrs.street_man or False
            result[adrs.id] = ' '.join([el for el in [street, number] if el])

        return result

    def _get_zip(self, cr, uid, ids, name, args, context=None):
        result = {i: {key: False
                      for key in [
                          'zip',
                          'city',
                      ]}
                  for i in ids}
        adrs_recs = self.browse(cr, uid, ids, context=context)
        for adrs in adrs_recs:
            result[adrs.id] = {
                'zip':
                adrs.address_local_zip_id
                and adrs.address_local_zip_id.local_zip or adrs.zip_man
                or False,
                'city':
                adrs.address_local_zip_id and adrs.address_local_zip_id.town
                or adrs.town_man or False,
            }

        return result

    _address_store_triggers = {
        # this MUST be executed in last for consistency: sequence is greater
        # than other
        'address.address':
        (lambda self, cr, uid, ids, context=None: ids, TRIGGER_FIELDS, 20),
        'address.local.zip':
        (lambda self, cr, uid, ids, context=None: self.pool[
            'address.local.zip']._get_linked_addresses(
                cr, uid, ids, context=context).ids, ['local_zip', 'town'], 15),
        'address.local.street':
        (lambda self, cr, uid, ids, context=None: self.pool[
            'address.local.street']._get_linked_addresses(
                cr, uid, ids, context=context),
         ['local_street', 'local_street_alternative'], 15),
        'res.country':
        (lambda self, cr, uid, ids, context=None: self.pool['res.country'].
         _get_linked_addresses(cr, uid, ids, context=context), ['name'], 15),
    }
    _zip_store_triggers = {
        'address.address': (lambda self, cr, uid, ids, context=None: ids,
                            ['address_local_zip_id', 'zip_man',
                             'town_man'], 10),
        'address.local.zip':
        (lambda self, cr, uid, ids, context=None: self.pool[
            'address.local.zip']._get_linked_addresses(
                cr, uid, ids, context=context).ids, ['local_zip', 'town'], 10),
    }
    _street_store_triggers = {
        'address.address': (lambda self, cr, uid, ids, context=None: ids, [
            'address_local_street_id',
            'select_alternative_address_local_street', 'street_man', 'number',
            'box'
        ], 10),
        'address.local.street':
        (lambda self, cr, uid, ids, context=None: self.pool[
            'address.local.street']._get_linked_addresses(
                cr, uid, ids, context=context),
         ['local_street', 'local_street_alternative'], 10),
    }

    _columns = {
        'id':
        fields.integer('ID', readonly=True),
        'name':
        fields.function(_get_integral_address,
                        string='Address',
                        type='char',
                        select=True,
                        multi='display_and_technical',
                        store=_address_store_triggers),
        'technical_name':
        fields.function(_get_integral_address,
                        string='Technical Name',
                        type='char',
                        select=True,
                        multi='display_and_technical',
                        store=_address_store_triggers),
        'country_id':
        fields.many2one('res.country',
                        'Country',
                        required=True,
                        select=True,
                        track_visibility='onchange'),
        'country_code':
        fields.related('country_id',
                       'code',
                       string='Country Code',
                       type='char'),
        'zip':
        fields.function(_get_zip,
                        string='Zip',
                        type='char',
                        multi='ZipAndCity',
                        store=_zip_store_triggers),
        'address_local_zip_id':
        fields.many2one('address.local.zip',
                        string='City',
                        track_visibility='onchange'),
        'zip_man':
        fields.char(string='Zip', track_visibility='onchange'),
        'city':
        fields.function(_get_zip,
                        string='City',
                        type='char',
                        multi='ZipAndCity',
                        store=_zip_store_triggers),
        'town_man':
        fields.char(string='Town', track_visibility='onchange'),
        'street':
        fields.function(_get_street,
                        string='Street',
                        type='char',
                        store=_street_store_triggers),
        'address_local_street_id':
        fields.many2one('address.local.street',
                        string='Reference Street',
                        track_visibility='onchange'),
        'select_alternative_address_local_street':
        fields.boolean('Use Alternative Reference Street',
                       track_visibility='onchange'),
        'street_man':
        fields.char(string='Street', track_visibility='onchange'),
        'street2':
        fields.char(string='Street2', track_visibility='onchange'),
        'number':
        fields.char(string='Number', track_visibility='onchange'),
        'box':
        fields.char(string='Box', track_visibility='onchange'),
        'sequence':
        fields.integer('Sequence',
                       track_visibility='onchange',
                       group_operator='min'),
        'postal_coordinate_ids':
        fields.one2many('postal.coordinate',
                        'address_id',
                        string='Postal Coordinates',
                        domain=[('active', '=', True)],
                        context={'force_recompute': True}),
        'postal_coordinate_inactive_ids':
        fields.one2many('postal.coordinate',
                        'address_id',
                        string='Postal Coordinates',
                        domain=[('active', '=', False)]),
    }

    _defaults = {
        'country_id':
        lambda self, cr, uid, c: self.pool.get('res.country').
        _country_default_get(cr, uid, COUNTRY_CODE, context=c),
        'country_code':
        COUNTRY_CODE,
        'sequence':
        0,
    }

    _order = 'country_id, zip, name'

    # constraints

    _unicity_keys = 'technical_name, sequence'

    # orm methods

    def copy_data(self, cr, uid, ids, default=None, context=None):
        """
        Increase sequence value when duplicating address
        """
        adr_id = isinstance(ids, (long, int)) and [ids] or ids
        technical_name = self.read(cr,
                                   uid,
                                   adr_id[0], ['technical_name'],
                                   context=context)['technical_name']
        cr.execute(
            'SELECT MAX(sequence) FROM %s WHERE technical_name=%%s' %
            (self._table, ), (technical_name, ))
        sequence = cr.fetchone()
        sequence = sequence and sequence[0] or False
        if not sequence:
            raise orm.except_orm(
                _('Error'),
                _('An Address without sequence number cannot be duplicated!'))

        default = dict(default or {})
        default.update({
            'sequence': sequence + 1,
            'postal_coordinate_ids': [],
            'postal_coordinate_inactive_ids': [],
        })
        res = super(address_address, self).copy_data(cr,
                                                     uid,
                                                     ids,
                                                     default=default,
                                                     context=context)
        return res

# view methods: onchange, button

    def onchange_country_id(self, cr, uid, ids, country_id, context=None):
        return {
            'value': {
                'country_code':
                self.pool.get('res.country').read(
                    cr, uid, [country_id], ['code'],
                    context=context)[0]['code'] if country_id else False,
                'address_local_zip_id':
                False,
            }
        }

    def onchange_local_zip_id(self, cr, uid, ids, local_zip_id, context=None):
        _zip, city = False, False
        if local_zip_id:
            zip_city = self.pool.get('address.local.zip').read(
                cr, uid, [local_zip_id], [], context=context)[0]
            _zip, city = zip_city['local_zip'], zip_city['town']
        return {
            'value': {
                'zip': _zip,
                'city': city,
                'zip_man': False,
                'town_man': False,
            }
        }

    def onchange_zip(self, cr, uid, ids, _zip, context=None):
        return {
            'value': {
                'address_local_street_id': False,
            }
        }

    def onchange_local_street_id(self,
                                 cr,
                                 uid,
                                 ids,
                                 local_street_id,
                                 context=None):
        vals = {} if local_street_id else {
            'select_alternative_address_local_street': False
        }
        vals.update({'street_man': False})
        return {'value': vals}


# public methods

    def get_linked_partners(self, cr, uid, ids, context=None):
        """
        Return all partners ids linked to addresses ids
        :param: ids
        :type: list of addresses ids
        :rparam: partner_ids
        :rtype: list of ids
        """
        coord_ids = self._get_linked_coordinates(cr, uid, ids, context=context)
        return self.pool['postal.coordinate'].get_linked_partners(
            cr, uid, coord_ids, context=context)
class kg_mail_queue(osv.osv):

	_name = "kg.mail.queue"
	_description = "Mail Queue"
	_order = "crt_date desc"

	_columns = {
				
		'source': fields.char('Source'),	
		'created_date':fields.date('Date'),
		'state': fields.selection([('pending','Pending'),('sent','Sent')],'Status', readonly=True),	
		'entry_mode': fields.selection([('auto','Auto'),('manual','Manual')],'Entry Mode', readonly=True),
		'company_id': fields.many2one('res.company', 'Company Name',readonly=True),
		'active': fields.boolean('Active'),
		'crt_date': fields.datetime('Creation Date',readonly=True),
		'user_id': fields.many2one('res.users', 'Created By', readonly=True),
		'mail_from': fields.char('From'),	
		'mail_to': fields.char('To'),	
		'mail_cc': fields.char('Cc'),	
		'mail_bcc': fields.char('Bcc'),	
		'attachment': fields.binary('Attachments'),	
		'transaction_id': fields.integer('Transaction ID'),	
		'subject': fields.char('Subject'),	
		'body': fields.html('Body'),	
		'sent_time': fields.datetime('Sent Time'),	
		'content_type': fields.selection([('mail','Mail'),('sms','SMS')],'Content Type'),	
		'body_1': fields.char('Body 1'),
		
	}
	
	_defaults = {
	
		'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'kg.mail.queue', context=c),
		'active': True,
		'state': 'pending',
		'user_id': lambda obj, cr, uid, context: uid,
		'crt_date': lambda * a: time.strftime('%Y-%m-%d %H:%M:%S'),
		'created_date': lambda * a: time.strftime('%Y-%m-%d'),
		'entry_mode': 'auto',
		'content_type': 'mail',
		'mail_from': '*****@*****.**',
		
	}

	### Basic Needs

	def entry_cancel(self,cr,uid,ids,context=None):
		rec = self.browse(cr,uid,ids[0])
		if rec.cancel_remark:
			self.write(cr, uid, ids, {'state': 'cancel','cancel_user_id': uid, 'cancel_date': time.strftime('%Y-%m-%d %H:%M:%S')})
		else:
			raise osv.except_osv(_('Cancel remark is must !!'),
				_('Enter the remarks in Cancel remarks field !!'))
		return True

	def entry_confirm(self,cr,uid,ids,context=None):
		self.write(cr, uid, ids, {'state': 'confirmed','confirm_user_id': uid, 'confirm_date': time.strftime('%Y-%m-%d %H:%M:%S')})
		return True
		
	def entry_draft(self,cr,uid,ids,context=None):
		self.write(cr, uid, ids, {'state': 'draft'})
		return True

	def entry_approve(self,cr,uid,ids,context=None):
		self.write(cr, uid, ids, {'state': 'approved','ap_rej_user_id': uid, 'ap_rej_date': time.strftime('%Y-%m-%d %H:%M:%S')})
		return True

	def entry_reject(self,cr,uid,ids,context=None):
		rec = self.browse(cr,uid,ids[0])
		if rec.remark:
			self.write(cr, uid, ids, {'state': 'reject','ap_rej_user_id': uid, 'ap_rej_date': time.strftime('%Y-%m-%d %H:%M:%S')})
		else:
			raise osv.except_osv(_('Rejection remark is must !!'),
				_('Enter the remarks in rejection remark field !!'))
		return True
		
	def unlink(self,cr,uid,ids,context=None):
		unlink_ids = []		
		for rec in self.browse(cr,uid,ids):	
			if rec.state not in ('draft','cancel'):				
				raise osv.except_osv(_('Warning!'),
						_('You can not delete this entry !!'))
			else:
				unlink_ids.append(rec.id)
		return osv.osv.unlink(self, cr, uid, unlink_ids, context=context)
		
	def write(self, cr, uid, ids, vals, context=None):
		vals.update({'update_date': time.strftime('%Y-%m-%d %H:%M:%S'),'update_user_id':uid})
		return super(kg_mail_queue, self).write(cr, uid, ids, vals, context)
		
		
	def send_mail(self,cr,uid,ids=0,context = None):
		today = date.today()
		que_search = self.search(cr,uid,[('created_date','=',today),('state','=','pending')])
		if que_search:
			for que_rec in self.browse(cr, uid, que_search, context=context):
				if que_rec.state == 'pending':
					email_from = [que_rec.mail_from]
					if que_rec.mail_to:
						email_to = [que_rec.mail_to]
					else:
						email_to = ['']			
					if que_rec.mail_cc:
						email_cc = [que_rec.mail_cc]
					else:
						email_cc = ['']		
					if que_rec.mail_bcc:
						email_bcc = [que_rec.mail_bcc]
					else:
						email_bcc = ['']	
					ir_mail_server = self.pool.get('ir.mail_server')
					msg = ir_mail_server.build_email(
						email_from = email_from[0],
						email_to = email_to,
						subject = que_rec.subject,
						body = que_rec.body_1,
						email_cc = email_cc,
						email_bcc = email_bcc,
						object_id = ids and ('%s-%s' % (ids, 'kg.mail.settings')),
						subtype = 'html',
						subtype_alternative = 'plain')
					res = ir_mail_server.send_email(cr, uid, msg,mail_server_id=1, context=context)
					self.write(cr,uid,que_rec.id,{'state':'sent','sent_time':time.strftime('%Y-%m-%d %H:%M:%S')})
				else:
					pass
		else:
			pass
			
		return True
		
	
	_constraints = [
	
	]
class view(osv.osv):
    _inherit = "ir.ui.view"
    _columns = {
        'inherit_option_id':
        fields.many2one('ir.ui.view', 'Optional Inheritancy'),
        'inherited_option_ids':
        fields.one2many('ir.ui.view', 'inherit_option_id',
                        'Optional Inheritancies'),
        'page':
        fields.boolean("Whether this view is a web page template (complete)"),
        'website_meta_title':
        fields.char("Website meta title", size=70, translate=True),
        'website_meta_description':
        fields.text("Website meta description", size=160, translate=True),
        'website_meta_keywords':
        fields.char("Website meta keywords", translate=True),
    }
    _defaults = {
        'page': False,
    }

    # Returns all views (called and inherited) related to a view
    # Used by translation mechanism, SEO and optional templates
    def _views_get(self,
                   cr,
                   uid,
                   view,
                   options=True,
                   context=None,
                   root=True,
                   stack_result=None):
        if not context:
            context = {}
        if not stack_result:
            stack_result = []

        def view_obj(view):
            if isinstance(view, basestring):
                mod_obj = self.pool.get("ir.model.data")
                m, n = view.split('.')
                view = mod_obj.get_object(cr, uid, m, n, context=context)
            elif isinstance(view, (int, long)):
                view = self.pool.get("ir.ui.view").browse(cr,
                                                          uid,
                                                          view,
                                                          context=context)
            return view

        try:
            view = view_obj(view)
        except ValueError:
            # Shall we log that ?
            return []

        while root and view.inherit_id:
            view = view.inherit_id

        result = [view]

        node = etree.fromstring(view.arch)
        for child in node.xpath("//t[@t-call]"):
            try:
                call_view = view_obj(child.get('t-call'))
            except ValueError:
                continue
            if call_view not in result:
                result += self._views_get(cr,
                                          uid,
                                          call_view,
                                          options=options,
                                          context=context,
                                          stack_result=result)

        todo = view.inherit_children_ids
        if options:
            todo += filter(lambda x: not x.inherit_id,
                           view.inherited_option_ids)
        # Keep options in a determinitic order whatever their enabled disabled status
        todo.sort(lambda x, y: cmp(x.id, y.id))
        for child_view in todo:
            for r in self._views_get(cr,
                                     uid,
                                     child_view,
                                     options=bool(child_view.inherit_id),
                                     context=context,
                                     root=False,
                                     stack_result=result):
                if r not in result:
                    result.append(r)
        return result

    def extract_embedded_fields(self, cr, uid, arch, context=None):
        return arch.xpath('//*[@data-oe-model != "ir.ui.view"]')

    def save_embedded_field(self, cr, uid, el, context=None):
        Model = self.pool[el.get('data-oe-model')]
        field = el.get('data-oe-field')

        column = Model._all_columns[field].column
        converter = self.pool['website.qweb'].get_converter_for(
            el.get('data-oe-type'))
        value = converter.from_html(cr, uid, Model, column, el)

        if value is not None:
            # TODO: batch writes?
            Model.write(cr,
                        uid, [int(el.get('data-oe-id'))], {field: value},
                        context=context)

    def to_field_ref(self, cr, uid, el, context=None):
        # filter out meta-information inserted in the document
        attributes = dict(
            (k, v) for k, v in el.items() if not k.startswith('data-oe-'))
        attributes['t-field'] = el.get('data-oe-expression')

        out = html.html_parser.makeelement(el.tag, attrib=attributes)
        out.tail = el.tail
        return out

    def replace_arch_section(self,
                             cr,
                             uid,
                             view_id,
                             section_xpath,
                             replacement,
                             context=None):
        # the root of the arch section shouldn't actually be replaced as it's
        # not really editable itself, only the content truly is editable.

        [view] = self.browse(cr, uid, [view_id], context=context)
        arch = etree.fromstring(view.arch.encode('utf-8'))
        # => get the replacement root
        if not section_xpath:
            root = arch
        else:
            # ensure there's only one match
            [root] = arch.xpath(section_xpath)

        root.text = replacement.text
        root.tail = replacement.tail
        # replace all children
        del root[:]
        for child in replacement:
            root.append(copy.deepcopy(child))

        return arch

    def save(self, cr, uid, res_id, value, xpath=None, context=None):
        """ Update a view section. The view section may embed fields to write

        :param str model:
        :param int res_id:
        :param str xpath: valid xpath to the tag to replace
        """
        res_id = int(res_id)

        arch_section = html.fromstring(
            value, parser=html.HTMLParser(encoding='utf-8'))

        if xpath is None:
            # value is an embedded field on its own, not a view section
            self.save_embedded_field(cr, uid, arch_section, context=context)
            return

        for el in self.extract_embedded_fields(cr,
                                               uid,
                                               arch_section,
                                               context=context):
            self.save_embedded_field(cr, uid, el, context=context)

            # transform embedded field back to t-field
            el.getparent().replace(
                el, self.to_field_ref(cr, uid, el, context=context))

        arch = self.replace_arch_section(cr,
                                         uid,
                                         res_id,
                                         xpath,
                                         arch_section,
                                         context=context)
        self.write(
            cr,
            uid,
            res_id,
            {'arch': etree.tostring(arch, encoding='utf-8').decode('utf-8')},
            context=context)
class ids_hr_employee_separation(osv.osv): 
    
    def separation_submit(self, cr, uid, ids, context=None):
        """Initiate workflow- submit the form. """
        self._check_resignations(cr, uid, ids, context=context)
        users= self.pool.get('res.users')
    	#code to update employee working status
    	self._update_employee_working_status(cr, uid, ids, 'on_resign', context=None)

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

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

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

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

    def _get_followup(self, cr, uid, context=None):
        if context is None:
            context = {}
        if context.get('active_model',
                       'ir.ui.menu') == 'account_followup.followup':
            return context.get('active_id', False)
        company_id = self.pool.get('res.users').browse(
            cr, uid, uid, context=context).company_id.id
        followp_id = self.pool.get('account_followup.followup').search(
            cr, uid, [('company_id', '=', company_id)], context=context)
        return followp_id and followp_id[0] or False

    def process_partners(self, cr, uid, partner_ids, data, context=None):
        partner_obj = self.pool.get('res.partner')
        partner_ids_to_print = []
        nbmanuals = 0
        manuals = {}
        nbmails = 0
        nbunknownmails = 0
        nbprints = 0
        resulttext = " "
        for partner in self.pool.get(
                'account_followup.stat.by.partner').browse(cr,
                                                           uid,
                                                           partner_ids,
                                                           context=context):
            if partner.max_followup_id.manual_action:
                partner_obj.do_partner_manual_action(cr,
                                                     uid,
                                                     [partner.partner_id.id],
                                                     context=context)
                nbmanuals = nbmanuals + 1
                key = partner.partner_id.payment_responsible_id.name or _(
                    "Anybody")
                if not key in manuals.keys():
                    manuals[key] = 1
                else:
                    manuals[key] = manuals[key] + 1
            if partner.max_followup_id.send_email:
                nbunknownmails += partner_obj.do_partner_mail(
                    cr, uid, [partner.partner_id.id], context=context)
                nbmails += 1
            if partner.max_followup_id.send_letter:
                partner_ids_to_print.append(partner.id)
                nbprints += 1
                message = _(
                    "Follow-up letter of "
                ) + "<I> " + partner.partner_id.latest_followup_level_id_without_lit.name + "</I>" + _(
                    " will be sent")
                partner_obj.message_post(cr,
                                         uid, [partner.partner_id.id],
                                         body=message,
                                         context=context)
        if nbunknownmails == 0:
            resulttext += str(nbmails) + _(" email(s) sent")
        else:
            resulttext += str(nbmails) + _(
                " email(s) should have been sent, but ") + str(
                    nbunknownmails) + _(
                        " had unknown email address(es)") + "\n <BR/> "
        resulttext += "<BR/>" + str(nbprints) + _(
            " letter(s) in report") + " \n <BR/>" + str(nbmanuals) + _(
                " manual action(s) assigned:")
        needprinting = False
        if nbprints > 0:
            needprinting = True
        resulttext += "<p align=\"center\">"
        for item in manuals:
            resulttext = resulttext + "<li>" + item + ":" + str(
                manuals[item]) + "\n </li>"
        resulttext += "</p>"
        result = {}
        action = partner_obj.do_partner_print(cr,
                                              uid,
                                              partner_ids_to_print,
                                              data,
                                              context=context)
        result['needprinting'] = needprinting
        result['resulttext'] = resulttext
        result['action'] = action or {}
        return result

    def do_update_followup_level(self,
                                 cr,
                                 uid,
                                 to_update,
                                 partner_list,
                                 date,
                                 context=None):
        #update the follow-up level on account.move.line
        for id in to_update.keys():
            if to_update[id]['partner_id'] in partner_list:
                self.pool.get('account.move.line').write(
                    cr, uid, [int(id)], {
                        'followup_line_id': to_update[id]['level'],
                        'followup_date': date
                    })

    def clear_manual_actions(self, cr, uid, partner_list, context=None):
        # Partnerlist is list to exclude
        # Will clear the actions of partners that have no due payments anymore
        partner_list_ids = [
            partner.partner_id.id
            for partner in self.pool.get('account_followup.stat.by.partner').
            browse(cr, uid, partner_list, context=context)
        ]
        ids = self.pool.get('res.partner').search(
            cr,
            uid, [
                '&', ('id', 'not in', partner_list_ids), '|',
                ('payment_responsible_id', '!=', False),
                ('payment_next_action_date', '!=', False)
            ],
            context=context)

        partners_to_clear = []
        for part in self.pool.get('res.partner').browse(cr,
                                                        uid,
                                                        ids,
                                                        context=context):
            if not part.unreconciled_aml_ids:
                partners_to_clear.append(part.id)
        self.pool.get('res.partner').action_done(cr,
                                                 uid,
                                                 partners_to_clear,
                                                 context=context)
        return len(partners_to_clear)

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

        #Get partners
        tmp = self._get_partners_followp(cr, uid, ids, context=context)
        partner_list = tmp['partner_ids']
        to_update = tmp['to_update']
        date = self.browse(cr, uid, ids, context=context)[0].date
        data = self.read(cr, uid, ids, [], context=context)[0]
        data['followup_id'] = data['followup_id'][0]

        #Update partners
        self.do_update_followup_level(cr,
                                      uid,
                                      to_update,
                                      partner_list,
                                      date,
                                      context=context)
        #process the partners (send mails...)
        restot = self.process_partners(cr,
                                       uid,
                                       partner_list,
                                       data,
                                       context=context)
        #clear the manual actions if nothing is due anymore
        nbactionscleared = self.clear_manual_actions(cr,
                                                     uid,
                                                     partner_list,
                                                     context=context)
        if nbactionscleared > 0:
            restot['resulttext'] = restot['resulttext'] + "<li>" + _(
                "%s partners have no credits and as such the action is cleared"
            ) % (str(nbactionscleared)) + "</li>"
        res = restot['action']

        #return the next action
        mod_obj = self.pool.get('ir.model.data')
        model_data_ids = mod_obj.search(
            cr,
            uid, [('model', '=', 'ir.ui.view'),
                  ('name', '=', 'view_account_followup_sending_results')],
            context=context)
        resource_id = mod_obj.read(cr,
                                   uid,
                                   model_data_ids,
                                   fields=['res_id'],
                                   context=context)[0]['res_id']
        context.update({
            'description': restot['resulttext'],
            'needprinting': restot['needprinting'],
            'report_data': res
        })
        return {
            'name': _('Send Letters and Emails: Actions Summary'),
            'view_type': 'form',
            'context': context,
            'view_mode': 'tree,form',
            'res_model': 'account_followup.sending.results',
            'views': [(resource_id, 'form')],
            'type': 'ir.actions.act_window',
            'target': 'new',
        }

    def _get_msg(self, cr, uid, context=None):
        return self.pool.get('res.users').browse(
            cr, uid, uid, context=context).company_id.follow_up_msg

    _defaults = {
        'date': lambda *a: time.strftime('%Y-%m-%d'),
        'followup_id': _get_followup,
        'email_body': "",
        'email_subject': _('Invoices Reminder'),
        'partner_lang': True,
    }

    def _get_partners_followp(self, cr, uid, ids, context=None):
        data = {}
        data = self.browse(cr, uid, ids, context=context)[0]
        company_id = data.company_id.id

        cr.execute(
            "SELECT l.partner_id, l.followup_line_id,l.date_maturity, l.date, l.id "\
            "FROM account_move_line AS l "\
                "LEFT JOIN account_account AS a "\
                "ON (l.account_id=a.id) "\
            "WHERE (l.reconcile_id IS NULL) "\
                "AND (a.type='receivable') "\
                "AND (l.state<>'draft') "\
                "AND (l.partner_id is NOT NULL) "\
                "AND (a.active) "\
                "AND (l.debit > 0) "\
                "AND (l.company_id = %s) " \
                "AND (l.blocked = False)" \
            "ORDER BY l.date", (company_id,))  #l.blocked added to take litigation into account and it is not necessary to change follow-up level of account move lines without debit
        move_lines = cr.fetchall()
        old = None
        fups = {}
        fup_id = 'followup_id' in context and context[
            'followup_id'] or data.followup_id.id
        date = 'date' in context and context['date'] or data.date

        current_date = datetime.date(*time.strptime(date, '%Y-%m-%d')[:3])
        cr.execute(
            "SELECT * "\
            "FROM account_followup_followup_line "\
            "WHERE followup_id=%s "\
            "ORDER BY delay", (fup_id,))

        #Create dictionary of tuples where first element is the date to compare with the due date and second element is the id of the next level
        for result in cr.dictfetchall():
            delay = datetime.timedelta(days=result['delay'])
            fups[old] = (current_date - delay, result['id'])
            old = result['id']

        partner_list = []
        to_update = {}

        #Fill dictionary of accountmovelines to_update with the partners that need to be updated
        for partner_id, followup_line_id, date_maturity, date, id in move_lines:
            if not partner_id:
                continue
            if followup_line_id not in fups:
                continue
            stat_line_id = partner_id * 10000 + company_id
            if date_maturity:
                if date_maturity <= fups[followup_line_id][0].strftime(
                        '%Y-%m-%d'):
                    if stat_line_id not in partner_list:
                        partner_list.append(stat_line_id)
                    to_update[str(id)] = {
                        'level': fups[followup_line_id][1],
                        'partner_id': stat_line_id
                    }
            elif date and date <= fups[followup_line_id][0].strftime(
                    '%Y-%m-%d'):
                if stat_line_id not in partner_list:
                    partner_list.append(stat_line_id)
                to_update[str(id)] = {
                    'level': fups[followup_line_id][1],
                    'partner_id': stat_line_id
                }
        return {'partner_ids': partner_list, 'to_update': to_update}
Example #19
0
			raise osv.except_osv(_('Error'), _("Error While Fetching Magento Stores!!!, %s")%e)
		for store in stores:
			if store['website']['is_default'] == '1':				
				store_info['website_id'] = int(store['website']['website_id'])
				store_info['store_id'] = view_pool._get_store_view(cr, uid, store, context)
				break;
		return store_info


	_columns = {
		'name': fields.char('Base URL', required=True, size=255 ,select=True),
		'instance_name': fields.char("Instance Name",size=64,select=True),
		'user':fields.char('API User Name', required=True, size=100),
		'pwd':fields.char('API Password',required=True, size=100),
		'status':fields.char('Connection Status',readonly=True, size=255),
		'active':fields.boolean('Active'),
		'store_id':fields.many2one('magento.store.view', 'Default Magento Store'),
		'group_id':fields.related('store_id', 'group_id', type="many2one", relation="magento.store", string="Default Store", readonly=True, store=True),
		'website_id':fields.related('group_id', 'website_id', type="many2one", relation="magento.website", string="Default Magento Website", readonly=True),
		'credential':fields.boolean('Show/Hide Credentials Tab', 
							help="If Enable, Credentials tab will be displayed, "
							"And after filling the details you can hide the Tab."),
		'auto_invoice':fields.boolean('Auto Invoice',
							help="If Enabled, Order will automatically Invoiced on Magento "
								" when Odoo order Get invoiced."),
		'auto_ship':fields.boolean('Auto Shipment', 
							help="If Enabled, Order will automatically shipped on Magento" 
								" when Odoo order Get Delivered."),
		'notify':fields.boolean('Notify Customer By Email', 
							help="If True, customer will be notify" 
								"during order shipment and invoice, else it won't."),
Example #20
0
class sale_order(osv.osv):
    _inherit = "sale.order"
    
    def copy(self, cr, uid, id, default=None, context=None):
        if not default:
            default = {}
        default.update({
            'shipped': False,
            'picking_ids': [],
        })
        return super(sale_order, self).copy(cr, uid, id, default, context=context)
    
    def shipping_policy_change(self, cr, uid, ids, policy, context=None):
        if not policy:
            return {}
        inv_qty = 'order'
        if policy == 'prepaid':
            inv_qty = 'order'
        elif policy == 'picking':
            inv_qty = 'procurement'
        return {'value': {'invoice_quantity': inv_qty}}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def has_stockable_products(self, cr, uid, ids, *args):
        for order in self.browse(cr, uid, ids):
            for order_line in order.order_line:
                if order_line.product_id and order_line.product_id.type in ('product', 'consu'):
                    return True
        return False
Example #21
0
    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
        result = super(product_search_ept, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu)
        if context is None:
            context={}
        self._columns = {}
        self._columns['product_ids'] = fields.text('Product IDS')
        if view_type != 'form':
            return result
        _moves_arch_lst = """
            <form string="Stone Search" version="7.0">
                  <div>
        """
        #_moves_arch_lst += """<group colspan="4" col="10">"""
        _line_fields = result['fields']
        info = [
                    {'model':None,'_column_name':'product_name','label':'Stone ID','type':'char','name':'name','product_search_type':'char'},
                    {'model':None,'_column_name':'product_certificate_no','label':'Certificate No.','type':'char','name':'certificate_no','product_search_type':'char'},
                    {'model':None,'_column_name':'product_weight','label':'Weight','no':3,'type':'float','name':'weight','product_search_type':'char','range':True},
                    {'model':None,'_column_name':'product_price_caret','label':'PPC','no':1,'type':'float','name':'price_caret','product_search_type':'char','range':True},
                    {'model':None,'_column_name':'product_discount','label':'Back%','no':1,'type':'float','name':'discount','product_search_type':'char','range':True},
                    {'model':'product.shape','width':'15%','_column_name':'product_shape','label':'SHP','help':'Shape','type':'many2one','name':'shape_id','product_search_type':'boolean','on_change':'product_shape_change'}, 
                    {'model':'product.color','width':'8%','_column_name':'product_color','label':'CLR','help':'Color','type':'many2one','name':'color_id','product_search_type':'boolean','on_change':'product_color_change'},
                    {'model':'product.clarity','width':'10%','_column_name':'product_clarity','label':'CLRTY','help':'Clarity','type':'many2one','name':'clarity_id','product_search_type':'boolean','on_change':'product_clarity_change'},
                    {'model':'product.cut','width':'12%','_column_name':'product_cut','label':'CUT','help':'Cut','type':'many2one','name':'cut_id','product_search_type':'boolean','on_change':'product_cut_change'},
                    {'model':'product.polish','width':'8%','_column_name':'product_polish','label':'POL','help':'Polish','type':'many2one','name':'polish_id','product_search_type':'boolean','on_change':'product_polish_change'},
                    {'model':'product.symmetry','width':'10%','_column_name':'product_symmetry','label':'SYM','help':'Symmetry','type':'many2one','name':'symmetry_id','product_search_type':'boolean','on_change':'product_symmetry_change'},
                    {'model':'product.fluorescence.intensity','width':'13%','_column_name':'product_fluorescence_intensity','label':'FLUR','help':'Fluorescence Intensity','type':'many2one','name':'fluorescence_intensity_id','product_search_type':'boolean','on_change':'product_fluorescence_intensity_change'},
                    {'model':'product.lab','width':'8%','_column_name':'product_lab','label':'LAB','help':'Lab','type':'many2one','name':'lab_id','product_search_type':'boolean','on_change':'product_lab_change'},
                    {'model':'product.fancy.color','width':'15%','_column_name':'product_fancy_color','label':'FNC CLR','help':'Fancy Color','type':'many2one','name':'fancy_color_id','product_search_type':'boolean','on_change':'product_fancy_color_change'},
                    {'model':'product.fancy.color.intensity','width':'15%','_column_name':'product1_fancy_color_intensity','label':'FNC CLR INT','help':'Fancy Color Intensity','type':'many2one','name':'fancy_color_intensity','product_search_type':'boolean','on_change':'product1_fancy_color_intensity_change'},
                    {'model':'product.fancy.color.overtone','width':'15%','_column_name':'product2_fancy_color_overtone','label':'FNC CLR OVR','help':'Fancy Color Overtone','type':'many2one','name':'fancy_color_overtone','product_search_type':'boolean','on_change':'product2_fancy_color_overtone_change'},
                    {'model':None,'_column_name':'product_status','width':'20%','label':'Status','type':'selection','name':'product_status','product_search_type':'boolean'
                              ,'selection_val':[('available','Available'),
                                                ('hold','Hold'),
                                                ('sold','Sold'),
                                               ('on_approval','On Approval'),
                                                ('on_consignment','On Consignment'),
                                                ('offline','Offline'),
                                                ('repair','Repair'),
                                                ('web_sale','Web Sale')]},
                    {'model':'stock.location','_column_name':'stock_location','width':'15%','label':'Location','type':'many2one','name':'location_id','product_search_type':'boolean'
                                    ,'domain':[('usage','=','internal')],},
                ]

        for model_info in info :        
            if model_info['type'] == 'many2one' and model_info['product_search_type'] == 'boolean' :
                if model_info['model']:
                    ids = self.pool.get(model_info['model']).search(cr,uid,model_info.get('domain',[]))
                    if ids :
                        _moves_arch_lst += """<div style="float:left;width:%s;">"""%(model_info.get('width', '100%'))
                        ''' Header '''
                        if model_info.get('label', False)=='Location':
                            _moves_arch_lst += """<u><label style="color:rgb(124,123,173);font-weight:bold;" string="%s"/></u>"""%(model_info['label'])
                        if model_info.get('on_change', False):
                            ''' Check box for Select All '''
                            _moves_arch_lst += """<div><field name="%s"  class="oe_inline"  
                                                         nolabel="1" 
                                                         on_change="%s(%s)"/>
                                                         """%(model_info['on_change'],model_info['on_change'],model_info['on_change'])
                            ''' Label for Select All '''                  
                            _moves_arch_lst += """<u><label help='%s' style="color:rgb(124, 123, 173);" string="%s" for="%s" /></u></div>"""%(model_info['help'],model_info['label'],model_info['label']) 
                            _line_fields.update({
                             '%s'%(model_info['on_change']) : {
                                 'string': 'All ?',
                                 'type' : 'boolean',
                            },})  
                            self._columns['%s'%(model_info['on_change'])] = fields.boolean(model_info['on_change'])                
                        for obj in self.pool.get(model_info['model']).browse(cr,uid,ids,context=context):
                            name=len(obj.name) > 7 and (obj.name[:7]+'...') or obj.name[:7]
                            _line_fields.update({
                             '%s%s'%(model_info['_column_name'],obj.id) : {
                                 'string': obj.name,
                                 'type' : 'boolean',
                                 'help' : '%s'%(obj.name)
                             },})
                            self._columns['%s%s'%(model_info['_column_name'],obj.id)] = fields.boolean(obj.name)
                        
                            ''' Check box and related label '''
                            _moves_arch_lst += """
                                 <div><field name="%s%s" class="oe_inline" nolabel="1"/>
                                 <label string="%s" for="%s%s" /></div>
                                 """%(model_info['_column_name'],obj.id,name,model_info['_column_name'],obj.id)

                        _moves_arch_lst += """</div>"""           
#######################            
            if model_info['type'] == 'char' and model_info['product_search_type'] == 'char':
                _moves_arch_lst += """<div style="width:%s;float:left;">""" %('50%')
                _line_fields.update({
                             '%s'%(model_info['_column_name']) : {
                                 'string': 'Name',
                                 'type' : 'char',
                                 'help' : '%s'%(model_info['_column_name']),
                             },})
                self._columns['%s'%(model_info['_column_name'])] = fields.char(model_info['label'],size=1024)
                _moves_arch_lst += """
                                <div>
                                    <label style="color:rgb(124, 123, 173);" string="%s" for="%s" />
                                    <field name="%s" style="width: 70%%"  nolabel="1"/>
                                </div>
                                </div>
                                 """%(model_info['label'],model_info['_column_name'],model_info['_column_name'])
  
################################
            if model_info['type'] == 'selection' and model_info['product_search_type'] == 'boolean' :
                if model_info['selection_val']:
                    _moves_arch_lst += """<div style="float:left;width:%s">"""%(model_info['width'])
                    _moves_arch_lst += """<u><label style="color:rgb(124, 123, 173);font-weight:bold;" string="%s" /></u><newline/>"""%(model_info['label'])
                    for value in model_info['selection_val']:
                        _line_fields.update({
                         '%s_%s'%(model_info['_column_name'],value[0]) : {
                             'string': value[1],
                             'type' : 'boolean',
                         },})
                        self._columns['%s_%s'%(model_info['_column_name'],value[0])] = fields.boolean(value[1])
                        _moves_arch_lst += """
                             <div><field name="%s_%s" nolabel="1"/>
                             <label string="%s" for="%s_%s" /></div>
                             """%(model_info['_column_name'],value[0],value[1],model_info['_column_name'],value[0])
                    _moves_arch_lst +="""</div>"""
###########################                        
            if model_info.get('range') and model_info['range']:
                width = '50%'
                if model_info.get('no') > 1:width = '100%'
                _moves_arch_lst += """<div style="float:left;width:%s;">"""%(width)
                _moves_arch_lst += """<div style="float:left;width:%s;"><label style="color:rgb(124, 123, 173);font-weight:bold;" string="%s" /></div>"""%('15%',model_info['label'])
                if model_info.get('no'):
                    no = model_info.get('no')
                    wid = str(85/int(no)) + '%'
                    while no != 0 :
                         
                        no = no - 1
                        _line_fields.update({'%s_from_%s'%(model_info['_column_name'],no) : {'string': model_info['label'],'type':'float'}})
                        _line_fields.update({'%s_to_%s'%(model_info['_column_name'],no) : {'string': model_info['label'],'type':'float'}})
                        self._columns['%s_from_%s'%(model_info['_column_name'],no)] = fields.float(model_info['label'],digits=(16,2))
                        self._columns['%s_to_%s'%(model_info['_column_name'],no)] = fields.float(model_info['label'],digits=(16,2))
                        _moves_arch_lst += """
                                        <div style="float:left;width:%s;"> 
                                             
                                             <div style="float:left;"><field name="%s_from_%s" placeholder="From" class="oe_inline" nolabel="1"/></div>
                                             <div style="float:left;"><b><label style="color:rgb(124, 123, 173);" string="--" /></b></div>
                                             <div style="float:left;"><field name="%s_to_%s" placeholder="To" class="oe_inline" nolabel="1"/></div>
                                             
                                        </div> 
                                     """%(wid,model_info['_column_name'],no,model_info['_column_name'],no)
                _moves_arch_lst += """</div>"""         
        _moves_arch_lst += """ 
                            </div>
                          <footer>
                          <button name="get_product" string="Search" type="object" colspan="2" class="oe_highlight"/>
                             or
                         <button string="Cancel" class="oe_link" special="cancel"/>
                          </footer>
                          </form>
                 """

        result['arch'] = _moves_arch_lst
        result['arch'] = result['arch'].replace('&','&amp;')
        result['fields'] = _line_fields
        return result       
Example #22
0
class ir_cron(osv.osv):
    """ Model describing cron jobs (also called actions or tasks).
    """

    # TODO: perhaps in the future we could consider a flag on ir.cron jobs
    # that would cause database wake-up even if the database has not been
    # loaded yet or was already unloaded (e.g. 'force_db_wakeup' or something)
    # See also openerp.cron

    _name = "ir.cron"
    _order = 'name'
    _columns = {
        'name': fields.char('Name', required=True),
        'user_id': fields.many2one('res.users', 'User', required=True),
        'active': fields.boolean('Active'),
        'interval_number': fields.integer('Interval Number',help="Repeat every x."),
        'interval_type': fields.selection( [('minutes', 'Minutes'),
            ('hours', 'Hours'), ('work_days','Work Days'), ('days', 'Days'),('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'),
        'numbercall': fields.integer('Number of Calls', help='How many times the method is called,\na negative number indicates no limit.'),
        'doall' : fields.boolean('Repeat Missed', help="Specify if missed occurrences should be executed when the server restarts."),
        'nextcall' : fields.datetime('Next Execution Date', required=True, help="Next planned execution date for this job."),
        'model': fields.char('Object', help="Model name on which the method to be called is located, e.g. 'res.partner'."),
        'function': fields.char('Method', help="Name of the method to be called when this job is processed."),
        'args': fields.text('Arguments', help="Arguments to be passed to the method, e.g. (uid,)."),
        'priority': fields.integer('Priority', help='The priority of the job, as an integer: 0 means higher priority, 10 means lower priority.')
    }

    _defaults = {
        'nextcall' : lambda *a: time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
        'priority' : 5,
        'user_id' : lambda obj,cr,uid,context: uid,
        'interval_number' : 1,
        'interval_type' : 'months',
        'numbercall' : 1,
        'active' : 1,
    }

    def _check_args(self, cr, uid, ids, context=None):
        try:
            for this in self.browse(cr, uid, ids, context):
                str2tuple(this.args)
        except Exception:
            return False
        return True

    _constraints = [
        (_check_args, 'Invalid arguments', ['args']),
    ]

    def _handle_callback_exception(self, cr, uid, model_name, method_name, args, job_id, job_exception):
        """ Method called when an exception is raised by a job.

        Simply logs the exception and rollback the transaction.

        :param model_name: model name on which the job method is located.
        :param method_name: name of the method to call when this job is processed.
        :param args: arguments of the method (without the usual self, cr, uid).
        :param job_id: job id.
        :param job_exception: exception raised by the job.

        """
        cr.rollback()

    def _callback(self, cr, uid, model_name, method_name, args, job_id):
        """ Run the method associated to a given job

        It takes care of logging and exception handling.

        :param model_name: model name on which the job method is located.
        :param method_name: name of the method to call when this job is processed.
        :param args: arguments of the method (without the usual self, cr, uid).
        :param job_id: job id.
        """
        try:
            args = str2tuple(args)
            openerp.modules.registry.RegistryManager.check_registry_signaling(cr.dbname)
            registry = openerp.registry(cr.dbname)
            if model_name in registry:
                model = registry[model_name]
                if hasattr(model, method_name):
                    log_depth = (None if _logger.isEnabledFor(logging.DEBUG) else 1)
                    netsvc.log(_logger, logging.DEBUG, 'cron.object.execute', (cr.dbname,uid,'*',model_name,method_name)+tuple(args), depth=log_depth)
                    if _logger.isEnabledFor(logging.DEBUG):
                        start_time = time.time()
                    getattr(model, method_name)(cr, uid, *args)
                    if _logger.isEnabledFor(logging.DEBUG):
                        end_time = time.time()
                        _logger.debug('%.3fs (%s, %s)' % (end_time - start_time, model_name, method_name))
                    openerp.modules.registry.RegistryManager.signal_caches_change(cr.dbname)
                else:
                    msg = "Method `%s.%s` does not exist." % (model_name, method_name)
                    _logger.warning(msg)
            else:
                msg = "Model `%s` does not exist." % model_name
                _logger.warning(msg)
        except Exception, e:
            _logger.exception("Call of self.pool.get('%s').%s(cr, uid, *%r) failed in Job %s" % (model_name, method_name, args, job_id))
            self._handle_callback_exception(cr, uid, model_name, method_name, args, job_id, e)
Example #23
0
from openerp.osv import orm, fields

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

FISCAL_POSITION_DEFAULTS = {
    'state': 'draft',
}


class AccountFiscalPositionTemplate(orm.Model):
Example #24
0
class view(osv.osv):
    _name = "ir.ui.view"
    _inherit = ["ir.ui.view", "website.seo.metadata"]
    _columns = {
        'page':
        fields.boolean("Whether this view is a web page template (complete)"),
        'customize_show':
        fields.boolean("Show As Optional Inherit"),
        'website_id':
        fields.many2one('website', ondelete='cascade', string="Website"),
    }

    _defaults = {
        'page': False,
        'customize_show': False,
    }

    def unlink(self, cr, uid, ids, context=None):
        res = super(view, self).unlink(cr, uid, ids, context=context)
        self.clear_caches()
        return res

    def _view_obj(self, cr, uid, view_id, context=None):
        if isinstance(view_id, basestring):
            if 'website_id' in (context or {}):
                domain = [('key', '=', view_id), '|',
                          ('website_id', '=', False),
                          ('website_id', '=', context.get('website_id'))]
                rec_id = self.search(cr,
                                     uid,
                                     domain,
                                     order='website_id',
                                     context=context)
            else:
                rec_id = self.search(cr,
                                     uid, [('key', '=', view_id)],
                                     context=context)
            if rec_id:
                return self.browse(cr, uid, rec_id, context=context)[0]
            else:
                return self.pool['ir.model.data'].xmlid_to_object(
                    cr, uid, view_id, raise_if_not_found=True, context=context)
        elif isinstance(view_id, (int, long)):
            return self.browse(cr, uid, view_id, context=context)

        # assume it's already a view object (WTF?)
        return view_id

    # Returns all views (called and inherited) related to a view
    # Used by translation mechanism, SEO and optional templates
    def _views_get(self,
                   cr,
                   uid,
                   view_id,
                   options=True,
                   bundles=False,
                   context=None,
                   root=True):
        """ For a given view ``view_id``, should return:

        * the view itself
        * all views inheriting from it, enabled or not
          - but not the optional children of a non-enabled child
        * all views called from it (via t-call)
        """

        try:
            view = self._view_obj(cr, uid, view_id, context=context)
        except ValueError:
            _logger.warning("Could not find view object with view_id '%s'" %
                            (view_id))
            # Shall we log that ? Yes, you should !
            return []

        while root and view.inherit_id:
            view = view.inherit_id

        result = [view]

        node = etree.fromstring(view.arch)
        xpath = "//t[@t-call]"
        if bundles:
            xpath += "| //t[@t-call-assets]"
        for child in node.xpath(xpath):
            try:
                called_view = self._view_obj(cr,
                                             uid,
                                             child.get(
                                                 't-call',
                                                 child.get('t-call-assets')),
                                             context=context)
            except ValueError:
                continue
            if called_view not in result:
                result += self._views_get(cr,
                                          uid,
                                          called_view,
                                          options=options,
                                          bundles=bundles,
                                          context=context)

        extensions = view.inherit_children_ids
        if not options:
            # only active children
            extensions = (v for v in view.inherit_children_ids if v.active)

        # Keep options in a deterministic order regardless of their applicability
        for extension in sorted(extensions, key=lambda v: v.id):
            for r in self._views_get(
                    cr,
                    uid,
                    extension,
                    # only return optional grandchildren if this child is enabled
                    options=extension.active,
                    context=context,
                    root=False):
                if r not in result:
                    result.append(r)
        return result

    @tools.ormcache_context('uid', 'xml_id', keys=('website_id', ))
    def get_view_id(self, cr, uid, xml_id, context=None):
        if context and 'website_id' in context and not isinstance(
                xml_id, (int, long)):
            domain = [('key', '=', xml_id), '|',
                      ('website_id', '=', context['website_id']),
                      ('website_id', '=', False)]
            [view_id] = self.search(
                cr, uid, domain, order='website_id', limit=1,
                context=context) or [None]
            if not view_id:
                raise ValueError('View %r in website %r not found' %
                                 (xml_id, context['website_id']))
        else:
            view_id = super(view, self).get_view_id(cr,
                                                    uid,
                                                    xml_id,
                                                    context=context)
        return view_id

    @api.cr_uid_ids_context
    def render(self,
               cr,
               uid,
               id_or_xml_id,
               values=None,
               engine='ir.qweb',
               context=None):
        if request and getattr(request, 'website_enabled', False):
            engine = 'ir.qweb'

            if isinstance(id_or_xml_id, list):
                id_or_xml_id = id_or_xml_id[0]

            qcontext = self._prepare_qcontext(cr, uid, context=context)

            # add some values
            if values:
                qcontext.update(values)

            # in edit mode ir.ui.view will tag nodes
            if not qcontext.get('translatable') and not qcontext.get(
                    'rendering_bundle'):
                if qcontext.get('editable'):
                    context = dict(context, inherit_branding=True)
                elif request.registry['res.users'].has_group(
                        cr, uid, 'base.group_website_publisher'):
                    context = dict(context, inherit_branding_auto=True)

            view_obj = request.website.get_template(id_or_xml_id)
            if 'main_object' not in qcontext:
                qcontext['main_object'] = view_obj

            values = qcontext

        return super(view, self).render(cr,
                                        uid,
                                        id_or_xml_id,
                                        values=values,
                                        engine=engine,
                                        context=context)

    def _prepare_qcontext(self, cr, uid, context=None):
        if not context:
            context = {}

        company = self.pool['res.company'].browse(
            cr, SUPERUSER_ID, request.website.company_id.id, context=context)

        editable = request.website.is_publisher()
        translatable = editable and context.get(
            'lang') != request.website.default_lang_code
        editable = not translatable and editable

        qcontext = dict(
            context.copy(),
            website=request.website,
            url_for=website.url_for,
            slug=website.slug,
            res_company=company,
            user_id=self.pool.get("res.users").browse(cr, uid, uid),
            default_lang_code=request.website.default_lang_code,
            languages=request.website.get_languages(),
            translatable=translatable,
            editable=editable,
            menu_data=self.pool['ir.ui.menu'].load_menus_root(
                cr, uid, context=context)
            if request.website.is_user() else None,
        )
        return qcontext

    def customize_template_get(self,
                               cr,
                               uid,
                               key,
                               full=False,
                               bundles=False,
                               context=None):
        """ Get inherit view's informations of the template ``key``. By default, only
        returns ``customize_show`` templates (which can be active or not), if
        ``full=True`` returns inherit view's informations of the template ``key``.
        ``bundles=True`` returns also the asset bundles
        """
        imd = self.pool['ir.model.data']
        theme_view_id = imd.xmlid_to_res_id(cr, uid, 'website.theme')
        user = self.pool['res.users'].browse(cr, uid, context=context)
        user_groups = set(user.groups_id)
        views = self._views_get(cr,
                                uid,
                                key,
                                bundles=bundles,
                                context=dict(context or {}, active_test=False))
        done = set()
        result = []
        for v in views:
            if not user_groups.issuperset(v.groups_id):
                continue
            if full or (v.customize_show and v.inherit_id.id != theme_view_id):
                if v.inherit_id not in done:
                    result.append({
                        'name': v.inherit_id.name,
                        'id': v.id,
                        'key': v.key,
                        'inherit_id': v.inherit_id.id,
                        'header': True,
                        'active': False
                    })
                    done.add(v.inherit_id)
                result.append({
                    'name': v.name,
                    'id': v.id,
                    'key': v.key,
                    'inherit_id': v.inherit_id.id,
                    'header': False,
                    'active': v.active,
                })
        return result
class stock_import_inventory(osv.osv_memory):
    _name = "stock.import.inventory"
    _description = "Import Inventory"

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

    _columns = {
        'location_id': fields.many2one('stock.location', 'Location', required=True),
        'import_file': fields.binary('File', filters="*.xls"),
        #to consider the product current inventory or not, if yes then add the current inventory to the upload excel quantity as the quantity to do physical inventory
        'consider_inventory': fields.boolean('Consider Current Inventory', select=True), 
        'all_done': fields.boolean('All Data Imported', readonly=True, select=True), 
        'result_line': fields.one2many('stock.import.inventory.result', 'import_id', 'Importing Result', readonly=True), 
        'file_template': fields.binary('Template File', readonly=True),
        'file_template_name': fields.char('Template File Name'),
    }
    
    def _get_template(self, cr, uid, context):
        cur_path = os.path.split(os.path.realpath(__file__))[0]
        path = os.path.join(cur_path,'stock_import_template.xls')
        data = open(path,'rb').read().encode('base64')
#        data = os.path.getsize(path)
        return data
    
    _defaults = {
        'location_id': _default_location,
Example #26
0
class Message(osv.Model):
    #TODO: turn off for data import only
    _log_access = True
    _name = "message.message"
    _order = "write_date desc,sequence"
    _description = 'UPDIS Message'
    _inherit = ['mail.thread', 'ir.needaction_mixin']

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

        return True


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

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

    def vote_unlike(self, cr, uid, user_id, message_id, context=None):
        message_vote_obj = self.pool.get('message.vote')
        message = self.read(cr, SUPERUSER_ID, int(message_id), ['vote_user_ids'], context=context)
        new_has_voted = not (user_id in message.get('vote_user_ids'))
        if new_has_voted:
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': False})
        else:
            self.write(cr, SUPERUSER_ID, [message.get('id')], {'vote_user_ids': [(3, user_id)]}, context=context)
            message_vote_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'user_id': user_id, 'up': False})
        return new_has_voted or False
Example #27
0
            ('file','File'),
            ('parser','Parser'),
        ],'Template source', select=True),
        'parser_def': fields.text('Parser Definition'),
        'parser_loc':fields.char('Parser location', size=128, help="Path to the parser location. Beginning of the path must be start with the module name!\nLike this: {module name}/{path to the parser.py file}"),
        'parser_state':fields.selection([
            ('default',_('Default')),
            ('def',_('Definition')),
            ('loc',_('Location')),
        ],'State of Parser', select=True),
        'in_format': fields.selection(_get_in_mimetypes, 'Template Mime-type'),
        'out_format':fields.many2one('report.mimetypes', 'Output Mime-type'),
        'report_sxw_content': fields.function(_report_content,
            fnct_inv=_report_content_inv, method=True,
            type='binary', string='SXW content',),
        'active':fields.boolean('Active', help='Disables the report if unchecked.'),
        'report_wizard':fields.boolean('Report Wizard'),
        'copies': fields.integer('Number of Copies'),
        'fallback_false':fields.boolean('Disable Format Fallback'),
        'xml_id': fields.function(_get_xml_id, type='char', size=128, string="XML ID",
                                  method=True, help="ID of the report defined in xml file"),
        'extras': fields.function(_get_extras, method=True, type='char', size='256', string='Extra options'),
        'deferred':fields.selection([
            ('off',_('Off')),
            ('adaptive',_('Adaptive')),
        ],'Deferred', help='Deferred (aka Batch) reporting, for reporting on large amount of data.'),
        'deferred_limit': fields.integer('Deferred Records Limit', help='Records limit at which you are invited to start the deferred process.'),
        'replace_report_id':fields.many2one('ir.actions.report.xml', 'Replace Report'),
        'wizard_id':fields.many2one('ir.actions.act_window', 'Wizard Action'),
    }
class session (osv.Model):
    _name = 'openacademy.session'
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    
    def compute_available_seats(self, seats, attendee_ids):
        if seats == 0 or len(attendee_ids) > seats:
            return 0.0
        else:
            return 100.0 - (float(len(attendee_ids)) / seats * 100)
    
    def get_available_seats(self, cr, uid, ids, field, arg, context={}):
        res = {}
        sessions = self.browse(cr, uid, ids, context=context)
        for session in sessions:
            res[session.id] = self.compute_available_seats(session.seats, session.attendee_ids)
        return res
    
    def onchange_seats(self, cr, uid, ids, seats, attendee_ids, context={}):
        res = {
            'value': {
                'available_seats': self.compute_available_seats(seats, attendee_ids)
                }
        }
        if seats < 0:
            res['warning'] = {
                'title':    _('Warning: wrong value'),
                'message':  _('The seats number cannot be negative.')
            }
        elif seats < len(attendee_ids):
            res['warning'] = {
                'title':    _('Warning: wrong value'),
                'message':  _('There is not enough seats for everyone.')
            }
        return res
    
    def _compute_end_date(self, cr, uid, ids, fields, arg, context={}):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            if session.start_date and session.duration:
                start_date = datetime.strptime(session.start_date, "%Y-%m-%d")
                duration = timedelta(days=(session.duration-1))
                end_date = start_date + duration
                res[session.id] = end_date.strftime('%Y-%m-%d')
            else:
                res[session.id] = session.start_date
        return res
    
    def _set_end_date(self, cr, uid, id, field, value, arg, context={}):
        session = self.browse(cr, uid, id, context=context)
        if session.start_date and value:
            start_date = datetime.strptime(session.start_date, "%Y-%m-%d")
            end_date = datetime.strptime(value[:10], "%Y-%m-%d")
            duration = end_date - start_date
            self.write(cr, uid, id, {'duration': (duration.days + 1)}, context=context)
    
    def _compute_hours(self, cr, uid, ids, fields, arg, context={}):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            res[session.id] = (session.duration * 24 if session.duration else 0)
            """
            if session.duration:
                res[session.id] = session.duration * 24
            else:
                res[session.id] = 0
                """
        return res
    
    def _compute_attendee_count(self, cr, uid, ids, fields, arg, context={}):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            res[session.id] = len(session.attendee_ids)
        return res
    
    def _set_hours(self, cr, uid, id, field, value, arg, context={}):
        if value:
            self.write(cr, uid, id, {'duration':(value/24)}, context=context)
    
    def action_draft(self, cr, uid, ids, context={}):
        return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
        
    def action_confirmed(self, cr, uid, ids, context={}):
        return self.write(cr, uid, ids, {'state': 'confirmed'}, context=context)
        
    def action_done(self, cr, uid, ids, context={}):
        return self.write(cr, uid, ids, {'state': 'done'}, context=context)
    
    _columns = {
        'name':         fields.char(string="Name", size=128, required=True, translate=True),
        'start_date':   fields.date(string="Start date"),
        'duration':     fields.float(string="Duration", digits=(6,2), help="Session durantion in days"),
        'seats':        fields.integer(string="Number of seats"),
        'instructor_id':fields.many2one('res.partner', string="Instructor", ondelete="set null",
                                        domain="['|',('instructor','=',True),('category_id.name','in',['Teacher level 1', 'Teacher level 2'])]"),
        'course_id':    fields.many2one('openacademy.course', string="Course", ondelete="cascade"),
        'attendee_ids': fields.one2many('openacademy.attendee', 'session_id', string="Attendees"),
        'available_seats':  fields.function(get_available_seats, type="float", string="Available Seats (%)", readonly=True),
        'active':       fields.boolean(string="Active", help="Uncheck this to deactivate this session. Beware, it will not appear anymore in the session list."),
        'end_date':     fields.function(_compute_end_date, fnct_inv=_set_end_date, type="date", string="End date"),
        'hours':        fields.function(_compute_hours, fnct_inv=_set_hours, type="float", string="Hours"),
        'attendee_count':   fields.function(_compute_attendee_count, type="integer", string="Attendee Count", store=True),
        'color':        fields.integer('Color'),
        'state':        fields.selection([('draft','Draft'),('confirmed','Confirmed'),('done','Done')], string="State"),
    }
    
    _defaults = {
        'start_date':   fields.date.today,
        'active':       True,
        'state':        'draft',
    }
    
    def _check_instructor_not_in_attendees(self, cr, uid, ids, context={}):
        for session in self.browse(cr, uid, ids, context=context):
            #partners = []
            #for attendee in session.attendee_ids:
            #    partners.append(attendee.partner_id)
            partners = [attendee.partner_id for attendee in session.attendee_ids]
            if session.instructor_id and session.instructor_id in partners:
                return False
        return True
    
    _constraints = [
        (_check_instructor_not_in_attendees,
        "The instructor cannot be also an attendee.",
        ['instructor_id', 'attendee_ids'])
    ]
    # Note: This are template style fields.
    # For nontemplate fields you might add aditional constraints to specific nontemplate fields (eg. company_id).
    # The chain method from itertools updates fields. Consider using this from within the nontemplate class when adding
    # new fields.

    # --- GENERAL SECTION ---

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

    # --- CRITERION SECTION ---

    '{0}_country'.format(ATTR_USE_DOM_COMPANY[0]): fields.many2one('res.country', 'Country'),
    '{0}_state'.format(ATTR_USE_DOM_COMPANY[0]): fields.many2one(
        'res.country.state', 'State',
        domain="[('country_id','=',{0}_country)]".format(ATTR_USE_DOM_COMPANY[0])),
    'to_{0}_country'.format(ATTR_USE_DOM_PINVOICE[0]): fields.many2one(
        'res.country', 'Country'),
    'to_{0}_state'.format(ATTR_USE_DOM_PINVOICE[0]): fields.many2one(
        'res.country.state', 'State',
        domain="[('country_id','=',to_{0}_country)]".format(ATTR_USE_DOM_PINVOICE[0])),
    'to_{0}_country'.format(ATTR_USE_DOM_PSHIPPER[0]): fields.many2one(
        'res.country', 'Country'),
    'to_{0}_state'.format(ATTR_USE_DOM_PSHIPPER[0]): fields.many2one(
Example #30
0
class res_partner(osv.osv):
    _inherit = 'res.partner'
    _description = 'Client'
    
    
    def check_client(self,cr,uid,ids,fields, arg,context={}):
        res = {}
        return res
        
        for o in self.browse(cr,uid,ids):
            res[o.id] = False
        
    
    
    def check_client2(self,cr,uid,ids,fields, arg,context={}):
        res={}
        
        
        for o in self.browse(cr,uid,ids):
            
            
            res[o.id] = {
                    'blocked_test':False,
                    'motif_blocage':False,
                     }
            
            # ignorer les le client comptoir et les fournisseur
            if o.id == 1052 or o.customer == False :
                continue

#            # Manque information
#            cin = o.cin or False
#            ice = o.ice or False
#            rc  =  o.rc or False
#            idfiscal  =  o.idfiscal or False

#            if not ((ice and rc and idfiscal) or cin) :
#                res[o.id] = True
#                continue
            
            
            # IMPAYE
            if o.test_impaye:
                impayee = sum([x.amount for x in o.paiement if  x.x_courant !='non' and x.date_impaye != False]) or False
                if impayee :
                    res[o.id] = {
                        'blocked_test':True,
                        'motif_blocage':u"Existance d'impayé",
                         }
                    continue
            
            
            
            # LIMITE DE CREDIT.
            if o.test_limite_credit and o.credit_limit >= 0:
                u" Total des commandes confirmées "
                orders = self.pool['sale.order'].search_read(cr,1,[('partner_id','=',o.id),('shipped','=',False),('invoiced','=',False),('state','not in',('draft','cancel','done'))],['amount_total','picking_ids'])
                
                picking_ids= [x['picking_ids'] for x in orders]
                picking_ids = reduce(lambda x,y:x+y, picking_ids,[])


                livraison_partiel = sum(self.pool['stock.picking'].browse(cr,1,picking_ids).filtered(lambda x:x.state !='cancel').mapped('total_cde')) or 0
                
                
                order_total = sum([x['amount_total'] for x in orders] ) or 0 - livraison_partiel
                
                # Pas de prsie en charge des commandes le 13/12/2018
                # order_total = 0

                u" Total de BL non facturés "
                bls = self.pool['stock.picking'].search_read(cr,1,[('state','=','done'),('invoice_state','!=','invoiced'),'|',('partner_id','=',o.id),('partner_dropship_id','=',o.id)],['total_cde'])
                bls_total = sum([x['total_cde'] for x in bls]) or 0
                
                u" Total des factures Brouillon "
                invoice_draft = self.pool['account.invoice'].search_read(cr,1,[('partner_id','=',o.id),('state','=','draft')],['amount_total'],context=context)
                invoice_draft_total = sum([x['amount_total'] for x in invoice_draft]) or 0
                
                u" Total des réglements non encaissés "
                non_encaissee = sum([x.amount for x in o.paiement if x.x_courant != 'non' and x.date_encaissement == False and x.journal_id.type=='bank']) or 0.0
                
                u" Avances et réglements non lettrés "
                avance = sum([x.writeoff_amount for x in o.paiement if x.x_courant != 'non' and (x.journal_id.type == 'cash' or x.date_encaissement != False) ]) or 0.0
                
                u" limite de crédit + avances > crédit + Cds + Bls + factures brouillon + Reglements non encaissés"
                if   (o.credit_limit + avance - (o.credit + non_encaissee + order_total + bls_total + invoice_draft_total )) <= 1.0 :
                    res[o.id] = {
                        'blocked_test':True,
                         'motif_blocage':u"Dépassement de limite de crédit",
                         }
                    continue

            
            # DATE D'ECHEANCES
            if o.test_echeance:
                date_echeance = dt.now() + relativedelta(days=-60)
                fact_ech = self.pool['account.invoice'].search(cr,1,[('partner_id','=',o.id),'|',('state','=','draft'),('residual','!=',0) ,'|',('date_invoice','<',date_echeance),'&',('date_invoice','=',False),('create_date','<',Fields.Datetime.to_string(date_echeance))])
                bl_ech   = self.pool['stock.picking'].search(cr,1,[('invoice_state','!=','invoiced'),('state','=','done'),'|',('partner_id','=',o.id),('partner_dropship_id','=',o.id) ,'|',('date_done','<',Fields.Datetime.to_string(date_echeance)),'&',('date_done','=',False),('create_date','<',Fields.Datetime.to_string(date_echeance))])
                
                if fact_ech or bl_ech :
                    res[o.id] = {
                         'blocked_test':True,
                         'motif_blocage':u"Au moins une facture ou un BL dépasse 60 jours de délai de réglement",
                         }
                    continue
            
            
            # REGELEMENT NON REMIS AU BANQUE A LA DATE D'ECHEANCE
            if o.test_reglement:
                non_remis = sum([x.amount for x in o.paiement if  x.x_courant !='non' and x.journal_id.type == 'bank' and x.date_remise == False and x.date < Fields.Datetime.to_string(dt.now())]) or False
                if non_remis :
                    res[o.id] = {
                        'blocked_test':True,
                         'motif_blocage':u" Au moins un réglement échu non remis en banque",
                         }
                    continue
            
            
            
            
            # les client Non vérifié seront bloqué pour vente crédit
            if o.verifie==False:
                res[o.id] = {
                        'blocked_test':True,
                        'motif_blocage': u"Ce client n'est pas vérifié!"
                         }
                continue
        return res or False
    
    
    
    _store = {
        'account.voucher':  ( lambda s,c,u,i,x:s.browse(c,u,i,x).partner_id.ids,None,10),
        
        'account.invoice':  ( lambda s,c,u,i,x: [inv.partner_id.id for inv in s.browse(c,u,i,x).filtered(lambda z:z.type in ('out_invoice','out_refund'))],None,10),
        
        'sale.order':       ( lambda s,c,u,i,x:s.browse(c,u,i,x).partner_id.ids,None,10),
        
        'stock.picking':    ( lambda s,c,u,i,x:s.browse(c,u,i,x).partner_id.ids,None,10),
        
        'res.partner':      (lambda s,c,u,i,x:i,None,10),
        
        
            }
    
    
    _columns = { 
        'rc':       fields.char(u'Registre de Commerce',oldname="RC"),
		'idfiscal':       fields.char(u'ID. Fiscal',oldname="IF"),
        'tp':       fields.char(u'Taxe professionnelle',oldname="TP"),
        'ice':      fields.char(u"Identifient Commun d'enreprise",oldname="ICE"),
        'cin':      fields.char(u"Carte d'Identite Nationale",oldname="CIN"),
        'zone':     fields.many2many('res.partner.zone','client_zone_rel','id_client','id_zone', string="Zones"),
        'blocked':  fields.function(check_client, string=u"Bloqué ?", type="boolean"),
        'paiement': fields.one2many('account.voucher','partner_id','Paiement', domain=[('journal_id.type', 'in', ['bank', 'cash']), ('type','=','receipt')]),
        'order_policy': fields.selection([('picking', u'Crédit'),('prepaid', u'Comptant')], u'Type de facturation', required=True,default="picking"),
        'agence' :  fields.many2many('res.agence','res_partner_agence_rel','partner_id','agence_id',string="Agence/client"),
        'picking_ids': fields.one2many('stock.picking','partner_id','Livraisons'),
        'blocked_test':  fields.function(check_client2, string=u"Bloqué2 ?", type="boolean",multi="all",store=_store),
        'motif_blocage': fields.function(check_client2, string="Motif de blocage",type="text",multi="all",store=_store),
        'test_limite_credit':   fields.boolean(u"Blocage sur limite de crédit ",default=True),
        'test_impaye':          fields.boolean(u"Blocage sur impayé ",default=True),
        'test_echeance':          fields.boolean(u"Blocage sur dépassement d''echéance ",default=True),
        'test_reglement':          fields.boolean(u"Blocage sur état de réglements ",default=True),
        'region_stat':  fields.many2one("res.partner.zone",u"Région du client"),
        'verifie':      fields.boolean(u"Ce client est vérifié pour gestion de risque automatique"),
        
        
        }
    
    _sql_constraints = [
        ('unique_rc', 'unique(rc)', u"RC doit être unique!"),
        ('unique_if', 'unique(idfiscal)', u"IF doit être unique!"),
        ('unique_tp', 'unique(tp)', u"TP doit être unique!"),
        ('unique_ice', 'unique(ice)', u"ICE doit être unique!"),
        ('unique_cin', 'unique(cin)', u"CIN doit être unique!"),
        ('unique_name', 'unique(name)', u"Name doit être unique!"),
        ('unique_ref', 'unique(ref)', u"Référence du client doit être unique!"),
    ] 


    

    def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100):
        if not args:
            args = []

        ids = []
        if len(name) > 1:
            ids = self.search(cr, user, [('ref', 'ilike', name)] + args, limit=limit, context=context)

        search_domain = [('name', operator, name)]
        if ids:
            search_domain.append(('id', 'not in', ids))
        ids.extend(self.search(cr, user, search_domain + args, limit=limit, context=context))

        locations = self.name_get(cr, user, ids, context)
        return sorted(locations, key=lambda (id, name): ids.index(id))
Example #31
0
class Partner(osv.osv):
    '''Partner'''
    _inherit = 'res.partner'

    def _get_partner_id(self, cr, uid, ids, context=None):
        member_line_obj = self.pool.get('membership.membership_line')
        res_obj = self.pool.get('res.partner')
        data_inv = member_line_obj.browse(cr, uid, ids, context=context)
        list_partner = []
        for data in data_inv:
            list_partner.append(data.partner.id)
        ids2 = list_partner
        while ids2:
            ids2 = res_obj.search(cr,
                                  uid, [('associate_member', 'in', ids2)],
                                  context=context)
            list_partner += ids2
        return list_partner

    def _get_invoice_partner(self, cr, uid, ids, context=None):
        inv_obj = self.pool.get('account.invoice')
        res_obj = self.pool.get('res.partner')
        data_inv = inv_obj.browse(cr, uid, ids, context=context)
        list_partner = []
        for data in data_inv:
            list_partner.append(data.partner_id.id)
        ids2 = list_partner
        while ids2:
            ids2 = res_obj.search(cr,
                                  uid, [('associate_member', 'in', ids2)],
                                  context=context)
            list_partner += ids2
        return list_partner

    def _cron_update_membership(self, cr, uid, context=None):
        partner_ids = self.search(cr,
                                  uid, [('membership_state', '=', 'paid')],
                                  context=context)
        if partner_ids:
            self._store_set_values(cr,
                                   uid,
                                   partner_ids, ['membership_state'],
                                   context=context)

    def _membership_state(self, cr, uid, ids, name, args, context=None):
        """This Function return Membership State For Given Partner.
        @param self: The object pointer
        @param cr: the current row, from the database cursor,
        @param uid: the current user’s ID for security checks,
        @param ids: List of Partner IDs
        @param name: Field Name
        @param context: A standard dictionary for contextual values
        @param return: Dictionary of Membership state Value
        """
        res = {}
        for id in ids:
            res[id] = 'none'
        today = time.strftime('%Y-%m-%d')
        for id in ids:
            partner_data = self.browse(cr, uid, id, context=context)
            if partner_data.membership_cancel and today > partner_data.membership_cancel:
                res[id] = 'free' if partner_data.free_member else 'canceled'
                continue
            if partner_data.membership_stop and today > partner_data.membership_stop:
                res[id] = 'free' if partner_data.free_member else 'old'
                continue
            s = 4
            if partner_data.member_lines:
                for mline in partner_data.member_lines:
                    if mline.date_to >= today and mline.date_from <= today:
                        if mline.account_invoice_line and mline.account_invoice_line.invoice_id:
                            mstate = mline.account_invoice_line.invoice_id.state
                            if mstate == 'paid':
                                s = 0
                                inv = mline.account_invoice_line.invoice_id
                                for payment in inv.payment_ids:
                                    if payment.invoice.type == 'out_refund':
                                        s = 2
                                break
                            elif mstate == 'open' and s != 0:
                                s = 1
                            elif mstate == 'cancel' and s != 0 and s != 1:
                                s = 2
                            elif (mstate == 'draft' or mstate
                                  == 'proforma') and s != 0 and s != 1:
                                s = 3
                if s == 4:
                    for mline in partner_data.member_lines:
                        if mline.date_from < today and mline.date_to < today and mline.date_from <= mline.date_to and mline.account_invoice_line and mline.account_invoice_line.invoice_id.state == 'paid':
                            s = 5
                        else:
                            s = 6
                if s == 0:
                    res[id] = 'paid'
                elif s == 1:
                    res[id] = 'invoiced'
                elif s == 2:
                    res[id] = 'canceled'
                elif s == 3:
                    res[id] = 'waiting'
                elif s == 5:
                    res[id] = 'old'
                elif s == 6:
                    res[id] = 'none'
            if partner_data.free_member and s != 0:
                res[id] = 'free'
            if partner_data.associate_member:
                res_state = self._membership_state(
                    cr,
                    uid, [partner_data.associate_member.id],
                    name,
                    args,
                    context=context)
                res[id] = res_state[partner_data.associate_member.id]
        return res

    def _membership_date(self, cr, uid, ids, name, args, context=None):
        """Return  date of membership"""
        name = name[0]
        res = {}
        member_line_obj = self.pool.get('membership.membership_line')
        for partner in self.browse(cr, uid, ids, context=context):
            if partner.associate_member:
                partner_id = partner.associate_member.id
            else:
                partner_id = partner.id
            res[partner.id] = {
                'membership_start': False,
                'membership_stop': False,
                'membership_cancel': False
            }
            if name == 'membership_start':
                line_id = member_line_obj.search(cr,
                                                 uid,
                                                 [('partner', '=', partner_id),
                                                  ('date_cancel', '=', False)],
                                                 limit=1,
                                                 order='date_from',
                                                 context=context)
                if line_id:
                    res[partner.id]['membership_start'] = member_line_obj.read(
                        cr, uid, [line_id[0]], ['date_from'],
                        context=context)[0]['date_from']

            if name == 'membership_stop':
                line_id1 = member_line_obj.search(
                    cr,
                    uid, [('partner', '=', partner_id),
                          ('date_cancel', '=', False)],
                    limit=1,
                    order='date_to desc',
                    context=context)
                if line_id1:
                    res[partner.id]['membership_stop'] = member_line_obj.read(
                        cr, uid, [line_id1[0]], ['date_to'],
                        context=context)[0]['date_to']

            if name == 'membership_cancel':
                if partner.membership_state == 'canceled':
                    line_id2 = member_line_obj.search(
                        cr,
                        uid, [('partner', '=', partner.id)],
                        limit=1,
                        order='date_cancel',
                        context=context)
                    if line_id2:
                        res[partner.
                            id]['membership_cancel'] = member_line_obj.read(
                                cr,
                                uid, [line_id2[0]], ['date_cancel'],
                                context=context)[0]['date_cancel']
        return res

    def _get_partners(self, cr, uid, ids, context=None):
        ids2 = ids
        while ids2:
            ids2 = self.search(cr,
                               uid, [('associate_member', 'in', ids2)],
                               context=context)
            ids += ids2
        return ids

    def __get_membership_state(self, *args, **kwargs):
        return self._membership_state(*args, **kwargs)

    _columns = {
        'associate_member':
        fields.many2one(
            'res.partner',
            'Associate Member',
            help=
            "A member with whom you want to associate your membership.It will consider the membership state of the associated member."
        ),
        'member_lines':
        fields.one2many('membership.membership_line', 'partner', 'Membership'),
        'free_member':
        fields.boolean('Free Member',
                       help="Select if you want to give free membership."),
        'membership_amount':
        fields.float('Membership Amount',
                     digits=(16, 2),
                     help='The price negotiated by the partner'),
        'membership_state':
        fields.function(
            __get_membership_state,
            string='Current Membership Status',
            type='selection',
            selection=STATE,
            store={
                'account.invoice': (_get_invoice_partner, ['state'], 10),
                'membership.membership_line': (_get_partner_id, ['state'], 10),
                'res.partner':
                (_get_partners,
                 ['free_member', 'membership_state', 'associate_member'], 10)
            },
            help='It indicates the membership state.\n'
            '-Non Member: A partner who has not applied for any membership.\n'
            '-Cancelled Member: A member who has cancelled his membership.\n'
            '-Old Member: A member whose membership date has expired.\n'
            '-Waiting Member: A member who has applied for the membership and whose invoice is going to be created.\n'
            '-Invoiced Member: A member whose invoice has been created.\n'
            '-Paying member: A member who has paid the membership fee.'),
        'membership_start':
        fields.function(_membership_date,
                        multi='membeship_start',
                        string='Membership Start Date',
                        type='date',
                        store={
                            'account.invoice':
                            (_get_invoice_partner, ['state'], 10),
                            'membership.membership_line': (
                                _get_partner_id,
                                ['state'],
                                10,
                            ),
                            'res.partner': (_get_partners, [
                                'free_member', 'membership_state',
                                'associate_member'
                            ], 10)
                        },
                        help="Date from which membership becomes active."),
        'membership_stop':
        fields.function(
            _membership_date,
            string='Membership End Date',
            type='date',
            multi='membership_stop',
            store={
                'account.invoice': (_get_invoice_partner, ['state'], 10),
                'membership.membership_line': (_get_partner_id, ['state'], 10),
                'res.partner':
                (_get_partners,
                 ['free_member', 'membership_state', 'associate_member'], 10)
            },
            help="Date until which membership remains active."),
        'membership_cancel':
        fields.function(
            _membership_date,
            string='Cancel Membership Date',
            type='date',
            multi='membership_cancel',
            store={
                'account.invoice': (_get_invoice_partner, ['state'], 11),
                'membership.membership_line': (_get_partner_id, ['state'], 10),
                'res.partner':
                (_get_partners,
                 ['free_member', 'membership_state', 'associate_member'], 10)
            },
            help="Date on which membership has been cancelled"),
    }
    _defaults = {
        'free_member': False,
        'membership_cancel': False,
    }

    def _check_recursion(self, cr, uid, ids, context=None):
        """Check  Recursive  for Associated Members.
        """
        level = 100
        while len(ids):
            cr.execute(
                'SELECT DISTINCT associate_member FROM res_partner WHERE id IN %s',
                (tuple(ids), ))
            ids = filter(None, map(lambda x: x[0], cr.fetchall()))
            if not level:
                return False
            level -= 1
        return True

    _constraints = [(_check_recursion,
                     'Error ! You cannot create recursive associated members.',
                     ['associate_member'])]

    def create_membership_invoice(self,
                                  cr,
                                  uid,
                                  ids,
                                  product_id=None,
                                  datas=None,
                                  context=None):
        """ Create Customer Invoice of Membership for partners.
        @param datas: datas has dictionary value which consist Id of Membership product and Cost Amount of Membership.
                      datas = {'membership_product_id': None, 'amount': None}
        """
        invoice_obj = self.pool.get('account.invoice')
        invoice_line_obj = self.pool.get('account.invoice.line')
        invoice_tax_obj = self.pool.get('account.invoice.tax')
        product_id = product_id or datas.get('membership_product_id', False)
        amount = datas.get('amount', 0.0)
        invoice_list = []
        if type(ids) in (
                int,
                long,
        ):
            ids = [ids]
        for partner in self.browse(cr, uid, ids, context=context):
            account_id = partner.property_account_receivable and partner.property_account_receivable.id or False
            fpos_id = partner.property_account_position and partner.property_account_position.id or False
            addr = self.address_get(cr, uid, [partner.id], ['invoice'])
            if partner.free_member:
                raise osv.except_osv(_('Error!'),
                                     _("Partner is a free Member."))
            if not addr.get('invoice', False):
                raise osv.except_osv(
                    _('Error!'),
                    _("Partner doesn't have an address to make the invoice."))
            quantity = 1
            line_value = {
                'product_id': product_id,
            }

            line_dict = invoice_line_obj.product_id_change(cr,
                                                           uid, {},
                                                           product_id,
                                                           False,
                                                           quantity,
                                                           '',
                                                           'out_invoice',
                                                           partner.id,
                                                           fpos_id,
                                                           price_unit=amount,
                                                           context=context)
            line_value.update(line_dict['value'])
            line_value['price_unit'] = amount
            if line_value.get('invoice_line_tax_id', False):
                tax_tab = [(6, 0, line_value['invoice_line_tax_id'])]
                line_value['invoice_line_tax_id'] = tax_tab

            invoice_id = invoice_obj.create(
                cr,
                uid, {
                    'partner_id': partner.id,
                    'account_id': account_id,
                    'fiscal_position': fpos_id or False
                },
                context=context)
            line_value['invoice_id'] = invoice_id
            invoice_line_obj.create(cr, uid, line_value, context=context)
            invoice_list.append(invoice_id)
            if line_value['invoice_line_tax_id']:
                tax_value = invoice_tax_obj.compute(cr, uid,
                                                    invoice_id).values()
                for tax in tax_value:
                    invoice_tax_obj.create(cr, uid, tax, context=context)
        #recompute the membership_state of those partners
        self.pool.get('res.partner').write(cr, uid, ids, {})
        return invoice_list
Example #32
0
class sale_order(orm.Model):
    _inherit = "sale.order"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        if account_move_ids:
            return True

        return False

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            else:
                return True

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

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

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

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

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

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

        return True

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

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

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

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

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

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

    def copy(self, cr, uid, ids, default={}, context=None):
        default = default or {}
        context = context or self.pool['res.users'].context_get(cr, uid)
        default.update({
            'validity': (datetime.today() + relativedelta(days=self.pool['res.users'].browse(cr, uid, uid, context).company_id.default_sale_order_validity or 0.0)).strftime(DEFAULT_SERVER_DATE_FORMAT),
            'tech_validation': False,
            'manager_validation': False,
            'customer_validation': False,
            'email_sent_validation': False,
            'supervisor_validation': False,
            'lost_reason_id': False
        })
        return super(sale_order, self).copy(cr, uid, ids, default, context=context)
Example #33
0
class hr_applicant(osv.Model):
    _name = "hr.applicant"
    _description = "Applicant"
    _order = "id desc"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

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

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

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

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

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

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

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

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

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

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

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

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

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

    _group_by_full = {'stage_id': _read_group_stage_ids}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def get_empty_list_help(self, cr, uid, help, context=None):
        context['empty_list_help_model'] = 'hr.job'
        context['empty_list_help_id'] = context.get('default_job_id', None)
        context['empty_list_help_document_name'] = _("job applicants")
        return super(hr_applicant, self).get_empty_list_help(cr,
                                                             uid,
                                                             help,
                                                             context=context)
Example #34
0
#This program is distributed in the hope that it will be useful,                #
#but WITHOUT ANY WARRANTY; without even the implied warranty of                 #
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                  #
#GNU General Public License for more details.                                   #
#                                                                               #
#You should have received a copy of the GNU General Public License              #
#along with this program.  If not, see <http://www.gnu.org/licenses/>.          #
#################################################################################

from openerp import pooler
from openerp.osv import fields, osv

TAX_CODE_COLUMNS = {
                    'domain':fields.char('Domain', size=32, 
                                         help="This field is only used if you develop your own module allowing developers to create specific taxes in a custom domain."),
                    'tax_discount': fields.boolean('Discount this Tax in Prince', 
                                                   help="Mark it for (ICMS, PIS, COFINS and others taxes included)."),
                    }

TAX_DEFAULTS = {
                'base_reduction': 0,
                'amount_mva': 0,
                }

class account_tax_code_template(osv.osv):
    """ Add fields used to define some brazilian taxes """
    _inherit = 'account.tax.code.template'
    _columns = TAX_CODE_COLUMNS

    def generate_tax_code(self, cr, uid, tax_code_root_id, company_id, 
                         context=None):
        """This function generates the tax codes from the templates of tax 
class stock_fill_inventory(osv.TransientModel):
    _inherit = "stock.fill.inventory"

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

    _columns = {
        'category_id':       fields.many2one('product.category', 'Category', required=False),
        'display_with_zero': fields.boolean('Add with zero quantity', required=False)
    }
 
    def fill_inventory(self, cr, uid, ids, context=None):
        """ To Import stock inventory according to products available in the selected locations.
        @param self: The object pointer.
        @param cr: A database cursor
        @param uid: ID of the user currently logged in
        @param ids: the ID or list of IDs if we want more than one
        @param context: A standard dictionary
        @return:
        """
        if context is None:
            context = {}

        _digits_id = self.pool.get('decimal.precision').search(cr, uid, [('name','=','Product Unit of Measure')])
Example #36
0
                break
            return {}

    def on_change_intervall(self, cr, uid, id, interval):
        ###Function that will update the cron
        ###freqeuence
        self.pool.get("currency.rate.update").save_cron(cr, uid, {"interval_type": interval})
        compagnies = self.search(cr, uid, [])
        for comp in compagnies:
            self.write(cr, uid, comp, {"interval_type": interval})
        return {}

    _inherit = "res.company"
    _columns = {
        ### activate the currency update
        "auto_currency_up": fields.boolean("Automatical update of the currency this company"),
        "services_to_use": fields.one2many("currency.rate.update.service", "company_id", "Currency update services"),
        ###predifine cron frequence
        "interval_type": fields.selection(
            [("days", "Day(s)"), ("weeks", "Week(s)"), ("months", "Month(s)")],
            "Currency update frequence",
            help="""changing this value will
                                                 also affect other compagnies""",
        ),
        ###function field that allows to know the
        ###mutli company currency implementation
        "multi_company_currency_enable": fields.function(
            _multi_curr_enable,
            method=True,
            type="boolean",
            string="Multi company currency",
                'amount_total': 0.0,
            }
            val = val1 = 0.0
            cur = order.pricelist_id.currency_id
            for line in order.order_line:
                val1 += line.price_subtotal
                val += self._amount_line_tax(cr, uid, line, context=context)
            res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val)
            res[order.id]['amount_untaxed'] = cur_obj.round(cr, uid, cur, val1)
            res[order.id]['amount_total'] = res[order.id]['amount_untaxed'] + res[order.id]['amount_tax']
        return res

    _columns = {
        'tot_volume': fields.function(_tot_volume, string='Total Volume', type='float'),
        'avg_volume': fields.function(_avg_volume, string='Average Volume', type='float'),
        'calculated' : fields.boolean('Amount Calculated'),
        'amount_untaxed': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Untaxed Amount',
            store={
                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line', 'calculated'], 10),
                'sale.order.line': (_get_order, ['purchase_price','price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
            },
            multi='sums', help="The amount without tax.", track_visibility='always'),
        'amount_tax': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Taxes',
            store={
                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
                'sale.order.line': (_get_order, ['purchase_price', 'price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
            },
            multi='sums', help="The tax amount."),
        'amount_total': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Total',
            store={
                'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line', 'calculated'], 10),
Example #38
0
			qty = line.qty2_2
			uom = line.uom_id.factor_inv
			qty_all = round(qty*uom,3)
			result[line.id] = qty_all
		return result

	_columns = {
		'name' : fields.char('Name', required=True),
		'partner_id' : fields.many2one('res.partner','Principle',domain=[('supplier','=',True)],required=True),
		'product_id' : fields.many2one('product.product','Bonus Product'),
		'qty_2' : fields.float('Bonus Qty2', digits_compute=dp.get_precision('Product Unit of Measure')),
		'qty' : fields.function(_qty_all_1,type="float",string='Bonus Qty',digits_compute=dp.get_precision('Product Unit of Measure')),
		'uom_id' : fields.many2one('product.uom','UoM',required=True),
		'uom_id2' : fields.many2one('product.uom','UoM',required=True),
		'value' : fields.float('Price Value',domain=[('is_percent','=',False)]),
		'per_product' : fields.boolean('Per Product'),
		'persentase' : fields.float('Percent Value', digits_compute= dp.get_precision('Discount'),domain=[('is_percent','=',True)]),
		'multi' : fields.boolean('Multiples'),
		'is_active' : fields.boolean('Active?'),
		'date_from' : fields.date('Start Date', required=True),
		'date_to' : fields.date('End Date', required=True),
		'condition_ids' : fields.one2many('master.condition','discount_id','Value Condition'),
		'condition2_ids' : fields.one2many('master.condition2','discount_id','Product Condition'),
		'condition3_ids' : fields.one2many('master.condition3','discount_id','Product Condition 2'),
		'condition4_ids' : fields.one2many('master.condition4','discount_id','Product Condition 3'),
		'condition5_ids' : fields.one2many('master.condition5','discount_id','Product Condition 4'),
		'group_price_ids' : fields.many2many('res.partner.category', id1='discount_id', id2='category_id', string='Group Price Category'),
		'is_percent' : fields.boolean('Is Percent'),
		'is_flat' : fields.boolean('Flat'),
		'type' :fields.selection([('regular','Regular Discount'),('promo','Promo Discount'),('extra','Extra Discount'),('cash','Cash Discount'),('mix','Mix Discount')],string='Type Discount',required=True),
		'min_qty_product' : fields.float('Min. Product Item',digits_compute=dp.get_precision('Product Unit of Measure')),
Example #39
0
#                                                                             #
#You should have received a copy of the GNU Affero General Public License     #
#along with this program.  If not, see <http://www.gnu.org/licenses/>.        #
###############################################################################

from openerp.osv import orm, fields

FISCAL_POSITION_COLUMNS = {
    'fiscal_category_id': fields.many2one('l10n_br_account.fiscal.category',
        'Categoria Fiscal'),
    'type': fields.selection([('input', 'Entrada'), ('output', 'Saida')],
        'Tipo'),
    'type_tax_use': fields.selection([('sale', 'Sale'),
                                      ('purchase', 'Purchase'),
                                      ('all', 'All')], 'Tax Application'),
    'inv_copy_note': fields.boolean('Copiar Observação na Nota Fiscal')}


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

    def onchange_type(self, cr, uid, ids, type=False, context=None):
        type_tax = {'input': 'purhcase', 'output': 'sale'}
        return {'value': {'type_tax_use': type_tax.get(type, 'all'),
                          'tax_ids': False}}

    def onchange_fiscal_category_id(self, cr, uid, ids,
                                    fiscal_category_id=False, context=None):
        if fiscal_category_id:
            fc_fields = self.pool.get('l10n_br_account.fiscal.category').read(
Example #40
0
class procurement_rule(osv.osv):
    _inherit = 'procurement.rule'

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

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

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

    _defaults = {
        'procure_method': 'make_to_stock',
        'propagate': True,
        'delay': 0,
    }
Example #41
0
class crm_lead(base_stage, format_address, osv.osv):
    """ CRM Lead Case """
    _name = "crm.lead"
    _description = "Lead/Opportunity"
    _order = "priority,date_action,id desc"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    _track = {
        'state': {
            'crm.mt_lead_create': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'new',
            'crm.mt_lead_won': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done',
            'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'cancel',
        },
        'stage_id': {
            'crm.mt_lead_stage': lambda self, cr, uid, obj, ctx=None: obj['state'] not in ['new', 'cancel', 'done'],
        },
    }

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {}
        if not vals.get('stage_id'):
            ctx = context.copy()
            if vals.get('section_id'):
                ctx['default_section_id'] = vals['section_id']
            if vals.get('type'):
                ctx['default_type'] = vals['type']
            vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
        return super(crm_lead, self).create(cr, uid, vals, context=context)

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

    def _get_default_stage_id(self, cr, uid, context=None):
        """ Gives default stage_id """
        section_id = self._get_default_section_id(cr, uid, context=context)
        return self.stage_find(cr, uid, [], section_id, [('state', '=', 'draft')], context=context)

    def _resolve_section_id_from_context(self, cr, uid, context=None):
        """ Returns ID of section based on the value of 'section_id'
            context key, or None if it cannot be resolved to a single
            Sales Team.
        """
        if context is None:
            context = {}
        if type(context.get('default_section_id')) in (int, long):
            return context.get('default_section_id')
        if isinstance(context.get('default_section_id'), basestring):
            section_name = context['default_section_id']
            section_ids = self.pool.get('crm.case.section').name_search(cr, uid, name=section_name, context=context)
            if len(section_ids) == 1:
                return int(section_ids[0][0])
        return None

    def _resolve_type_from_context(self, cr, uid, context=None):
        """ Returns the type (lead or opportunity) from the type context
            key. Returns None if it cannot be resolved.
        """
        if context is None:
            context = {}
        return context.get('default_type')

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

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

    def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
        res = super(crm_lead,self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
        if view_type == 'form':
            res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context)
        return res

    _group_by_full = {
        'stage_id': _read_group_stage_ids
    }

    def _compute_day(self, cr, uid, ids, fields, args, context=None):
        """
        :return dict: difference between current date and log date
        """
        cal_obj = self.pool.get('resource.calendar')
        res_obj = self.pool.get('resource.resource')

        res = {}
        for lead in self.browse(cr, uid, ids, context=context):
            for field in fields:
                res[lead.id] = {}
                duration = 0
                ans = False
                if field == 'day_open':
                    if lead.date_open:
                        date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
                        date_open = datetime.strptime(lead.date_open, "%Y-%m-%d %H:%M:%S")
                        ans = date_open - date_create
                        date_until = lead.date_open
                elif field == 'day_close':
                    if lead.date_closed:
                        date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
                        date_close = datetime.strptime(lead.date_closed, "%Y-%m-%d %H:%M:%S")
                        date_until = lead.date_closed
                        ans = date_close - date_create
                if ans:
                    resource_id = False
                    if lead.user_id:
                        resource_ids = res_obj.search(cr, uid, [('user_id','=',lead.user_id.id)])
                        if len(resource_ids):
                            resource_id = resource_ids[0]

                    duration = float(ans.days)
                    if lead.section_id and lead.section_id.resource_calendar_id:
                        duration =  float(ans.days) * 24
                        new_dates = cal_obj.interval_get(cr,
                            uid,
                            lead.section_id.resource_calendar_id and lead.section_id.resource_calendar_id.id or False,
                            datetime.strptime(lead.create_date, '%Y-%m-%d %H:%M:%S'),
                            duration,
                            resource=resource_id
                        )
                        no_days = []
                        date_until = datetime.strptime(date_until, '%Y-%m-%d %H:%M:%S')
                        for in_time, out_time in new_dates:
                            if in_time.date not in no_days:
                                no_days.append(in_time.date)
                            if out_time > date_until:
                                break
                        duration =  len(no_days)
                res[lead.id][field] = abs(int(duration))
        return res

    def _history_search(self, cr, uid, obj, name, args, context=None):
        res = []
        msg_obj = self.pool.get('mail.message')
        message_ids = msg_obj.search(cr, uid, [('email_from','!=',False), ('subject', args[0][1], args[0][2])], context=context)
        lead_ids = self.search(cr, uid, [('message_ids', 'in', message_ids)], context=context)

        if lead_ids:
            return [('id', 'in', lead_ids)]
        else:
            return [('id', '=', '0')]

    _columns = {
        'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null', track_visibility='onchange',
            select=True, help="Linked partner (optional). Usually created when converting the lead."),

        'id': fields.integer('ID', readonly=True),
        'name': fields.char('Subject', size=64, required=True, select=1),
        'active': fields.boolean('Active', required=False),
        'date_action_last': fields.datetime('Last Action', readonly=1),
        'date_action_next': fields.datetime('Next Action', readonly=1),
        'email_from': fields.char('Email', size=128, help="Email address of the contact", select=1),
        'section_id': fields.many2one('crm.case.section', 'Sales Team',
                        select=True, track_visibility='onchange', help='When sending mails, the default email address is taken from the sales team.'),
        'create_date': fields.datetime('Creation Date' , readonly=True),
        'email_cc': fields.text('Global CC', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
        'description': fields.text('Notes'),
        'write_date': fields.datetime('Update Date' , readonly=True),
        'categ_ids': fields.many2many('crm.case.categ', 'crm_lead_category_rel', 'lead_id', 'category_id', 'Categories', \
            domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]"),
        'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \
            domain="['|',('section_id','=',section_id),('section_id','=',False)]", help="From which campaign (seminar, marketing campaign, mass mailing, ...) did this contact come from?"),
        'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel (mail, direct, phone, ...)"),
        'contact_name': fields.char('Contact Name', size=64),
        'partner_name': fields.char("Customer Name", size=64,help='The name of the future partner company that will be created while converting the lead into opportunity', select=1),
        'opt_out': fields.boolean('Opt-Out', oldname='optout', help="If opt-out is checked, this contact has refused to receive emails or unsubscribed to a campaign."),
        'type':fields.selection([ ('lead','Lead'), ('opportunity','Opportunity'), ],'Type', help="Type is used to separate Leads and Opportunities"),
        'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
        'date_closed': fields.datetime('Closed', readonly=True),
        'stage_id': fields.many2one('crm.case.stage', 'Stage', track_visibility='onchange',
                        domain="['&', '&', ('fold', '=', False), ('section_ids', '=', section_id), '|', ('type', '=', type), ('type', '=', 'both')]"),
        'user_id': fields.many2one('res.users', 'Salesperson', select=True, track_visibility='onchange'),
        'referred': fields.char('Referred By', size=64),
        'date_open': fields.datetime('Opened', readonly=True),
        'day_open': fields.function(_compute_day, string='Days to Open', \
                                multi='day_open', type="float", store=True),
        'day_close': fields.function(_compute_day, string='Days to Close', \
                                multi='day_close', type="float", store=True),
        'state': fields.related('stage_id', 'state', type="selection", store=True,
                selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
                help='The Status is set to \'Draft\', when a case is created. If the case is in progress the Status is set to \'Open\'. When the case is over, the Status is set to \'Done\'. If the case needs to be reviewed then the Status is  set to \'Pending\'.'),

        # Only used for type opportunity
        'probability': fields.float('Success Rate (%)',group_operator="avg"),
        'planned_revenue': fields.float('Expected Revenue', track_visibility='always'),
        'ref': fields.reference('Reference', selection=crm._links_get, size=128),
        'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
        'phone': fields.char("Phone", size=64),
        'date_deadline': fields.date('Expected Closing', help="Estimate of the date on which the opportunity will be won."),
        'date_action': fields.date('Next Action Date', select=True),
        'title_action': fields.char('Next Action', size=64),
        'color': fields.integer('Color Index'),
        'partner_address_name': fields.related('partner_id', 'name', type='char', string='Partner Contact Name', readonly=True),
        'partner_address_email': fields.related('partner_id', 'email', type='char', string='Partner Contact Email', readonly=True),
        'company_currency': fields.related('company_id', 'currency_id', type='many2one', string='Currency', readonly=True, relation="res.currency"),
        'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
        'user_login': fields.related('user_id', 'login', type='char', string='User Login', readonly=True),

        # Fields for address, due to separation from crm and res.partner
        'street': fields.char('Street', size=128),
        'street2': fields.char('Street2', size=128),
        'zip': fields.char('Zip', change_default=True, size=24),
        'city': fields.char('City', size=128),
        'state_id': fields.many2one("res.country.state", 'State'),
        'country_id': fields.many2one('res.country', 'Country'),
        'phone': fields.char('Phone', size=64),
        'fax': fields.char('Fax', size=64),
        'mobile': fields.char('Mobile', size=64),
        'function': fields.char('Function', size=128),
        'title': fields.many2one('res.partner.title', 'Title'),
        'company_id': fields.many2one('res.company', 'Company', select=1),
        'payment_mode': fields.many2one('crm.payment.mode', 'Payment Mode', \
                            domain="[('section_id','=',section_id)]"),
        'planned_cost': fields.float('Planned Costs'),
    }

    _defaults = {
        'active': 1,
        'type': 'lead',
        'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
        'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
        'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
        'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
        'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
        'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
        'color': 0,
    }

    _sql_constraints = [
        ('check_probability', 'check(probability >= 0 and probability <= 100)', 'The probability of closing the deal should be between 0% and 100%!')
    ]

    def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
        if not stage_id:
            return {'value':{}}
        stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context)
        if not stage.on_change:
            return {'value':{}}
        return {'value':{'probability': stage.probability}}

    def on_change_partner(self, cr, uid, ids, partner_id, context=None):
        result = {}
        values = {}
        if partner_id:
            partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
            values = {
                'partner_name' : partner.name,
                'street' : partner.street,
                'street2' : partner.street2,
                'city' : partner.city,
                'state_id' : partner.state_id and partner.state_id.id or False,
                'country_id' : partner.country_id and partner.country_id.id or False,
                'email_from' : partner.email,
                'phone' : partner.phone,
                'mobile' : partner.mobile,
                'fax' : partner.fax,
            }
        return {'value' : values}

    def _check(self, cr, uid, ids=False, context=None):
        """ Override of the base.stage method.
            Function called by the scheduler to process cases for date actions
            Only works on not done and cancelled cases
        """
        cr.execute('select * from crm_case \
                where (date_action_last<%s or date_action_last is null) \
                and (date_action_next<=%s or date_action_next is null) \
                and state not in (\'cancel\',\'done\')',
                (time.strftime("%Y-%m-%d %H:%M:%S"),
                    time.strftime('%Y-%m-%d %H:%M:%S')))

        ids2 = map(lambda x: x[0], cr.fetchall() or [])
        cases = self.browse(cr, uid, ids2, context=context)
        return self._action(cr, uid, cases, False, context=context)

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

    def case_cancel(self, cr, uid, ids, context=None):
        """ Overrides case_cancel from base_stage to set probability """
        res = super(crm_lead, self).case_cancel(cr, uid, ids, context=context)
        self.write(cr, uid, ids, {'probability' : 0.0}, context=context)
        return res

    def case_reset(self, cr, uid, ids, context=None):
        """ Overrides case_reset from base_stage to set probability """
        res = super(crm_lead, self).case_reset(cr, uid, ids, context=context)
        self.write(cr, uid, ids, {'probability': 0.0}, context=context)
        return res

    def case_mark_lost(self, cr, uid, ids, context=None):
        """ Mark the case as lost: state=cancel and probability=0 """
        for lead in self.browse(cr, uid, ids):
            stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0),('on_change','=',True)], context=context)
            if stage_id:
                self.case_set(cr, uid, [lead.id], values_to_update={'probability': 0.0}, new_stage_id=stage_id, context=context)
        return True

    def case_mark_won(self, cr, uid, ids, context=None):
        """ Mark the case as won: state=done and probability=100 """
        for lead in self.browse(cr, uid, ids):
            stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0),('on_change','=',True)], context=context)
            if stage_id:
                self.case_set(cr, uid, [lead.id], values_to_update={'probability': 100.0}, new_stage_id=stage_id, context=context)
        return True

    def set_priority(self, cr, uid, ids, priority):
        """ Set lead priority
        """
        return self.write(cr, uid, ids, {'priority' : priority})

    def set_high_priority(self, cr, uid, ids, context=None):
        """ Set lead priority to high
        """
        return self.set_priority(cr, uid, ids, '1')

    def set_normal_priority(self, cr, uid, ids, context=None):
        """ Set lead priority to normal
        """
        return self.set_priority(cr, uid, ids, '3')

    def _merge_get_result_type(self, cr, uid, opps, context=None):
        """
        Define the type of the result of the merge.  If at least one of the
        element to merge is an opp, the resulting new element will be an opp.
        Otherwise it will be a lead.

        We'll directly use a list of browse records instead of a list of ids
        for performances' sake: it will spare a second browse of the
        leads/opps.

        :param list opps: list of browse records containing the leads/opps to process
        :return string type: the type of the final element
        """
        for opp in opps:
            if (opp.type == 'opportunity'):
                return 'opportunity'

        return 'lead'

    def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
        """
        Prepare lead/opp data into a dictionary for merging.  Different types
        of fields are processed in different ways:
        - text: all the values are concatenated
        - m2m and o2m: those fields aren't processed
        - m2o: the first not null value prevails (the other are dropped)
        - any other type of field: same as m2o

        :param list ids: list of ids of the leads to process
        :param list fields: list of leads' fields to process
        :return dict data: contains the merged values
        """
        opportunities = self.browse(cr, uid, ids, context=context)

        def _get_first_not_null(attr):
            for opp in opportunities:
                if hasattr(opp, attr) and bool(getattr(opp, attr)):
                    return getattr(opp, attr)
            return False

        def _get_first_not_null_id(attr):
            res = _get_first_not_null(attr)
            return res and res.id or False

        def _concat_all(attr):
            return '\n\n'.join(filter(lambda x: x, [getattr(opp, attr) or '' for opp in opportunities if hasattr(opp, attr)]))

        # Process the fields' values
        data = {}
        for field_name in fields:
            field_info = self._all_columns.get(field_name)
            if field_info is None:
                continue
            field = field_info.column
            if field._type in ('many2many', 'one2many'):
                continue
            elif field._type == 'many2one':
                data[field_name] = _get_first_not_null_id(field_name)  # !!
            elif field._type == 'text':
                data[field_name] = _concat_all(field_name)  #not lost
            else:
                data[field_name] = _get_first_not_null(field_name)  #not lost

        # Define the resulting type ('lead' or 'opportunity')
        data['type'] = self._merge_get_result_type(cr, uid, opportunities, context)
        return data

    def _mail_body(self, cr, uid, lead, fields, title=False, context=None):
        body = []
        if title:
            body.append("%s\n" % (title))

        for field_name in fields:
            field_info = self._all_columns.get(field_name)
            if field_info is None:
                continue
            field = field_info.column
            value = ''

            if field._type == 'selection':
                if hasattr(field.selection, '__call__'):
                    key = field.selection(self, cr, uid, context=context)
                else:
                    key = field.selection
                value = dict(key).get(lead[field_name], lead[field_name])
            elif field._type == 'many2one':
                if lead[field_name]:
                    value = lead[field_name].name_get()[0][1]
            elif field._type == 'many2many':
                if lead[field_name]:
                    for val in lead[field_name]:
                        field_value = val.name_get()[0][1]
                        value += field_value + ","
            else:
                value = lead[field_name]

            body.append("%s: %s" % (field.string, value or ''))
        return "<br/>".join(body + ['<br/>'])

    def _merge_notify(self, cr, uid, opportunity_id, opportunities, context=None):
        """
        Create a message gathering merged leads/opps information.
        """
        #TOFIX: mail template should be used instead of fix body, subject text
        details = []
        result_type = self._merge_get_result_type(cr, uid, opportunities, context)
        if result_type == 'lead':
            merge_message = _('Merged leads')
        else:
            merge_message = _('Merged opportunities')
        subject = [merge_message]
        for opportunity in opportunities:
            subject.append(opportunity.name)
            title = "%s : %s" % (opportunity.type == 'opportunity' and _('Merged opportunity') or _('Merged lead'), opportunity.name)
            fields = list(CRM_LEAD_FIELDS_TO_MERGE)
            details.append(self._mail_body(cr, uid, opportunity, fields, title=title, context=context))

        # Chatter message's subject
        subject = subject[0] + ": " + ", ".join(subject[1:])
        details = "\n\n".join(details)
        return self.message_post(cr, uid, [opportunity_id], body=details, subject=subject, context=context)

    def _merge_opportunity_history(self, cr, uid, opportunity_id, opportunities, context=None):
        message = self.pool.get('mail.message')
        for opportunity in opportunities:
            for history in opportunity.message_ids:
                message.write(cr, uid, history.id, {
                        'res_id': opportunity_id,
                        'subject' : _("From %s : %s") % (opportunity.name, history.subject)
                }, context=context)

        return True

    def _merge_opportunity_attachments(self, cr, uid, opportunity_id, opportunities, context=None):
        attachment = self.pool.get('ir.attachment')

        # return attachments of opportunity
        def _get_attachments(opportunity_id):
            attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', opportunity_id)], context=context)
            return attachment.browse(cr, uid, attachment_ids, context=context)

        count = 1
        first_attachments = _get_attachments(opportunity_id)
        for opportunity in opportunities:
            attachments = _get_attachments(opportunity.id)
            for first in first_attachments:
                for attachment in attachments:
                    if attachment.name == first.name:
                        values = dict(
                            name = "%s (%s)" % (attachment.name, count,),
                            res_id = opportunity_id,
                        )
                        attachment.write(values)
                        count+=1

        return True

    def merge_opportunity(self, cr, uid, ids, context=None):
        """
        Different cases of merge:
        - merge leads together = 1 new lead
        - merge at least 1 opp with anything else (lead or opp) = 1 new opp

        :param list ids: leads/opportunities ids to merge
        :return int id: id of the resulting lead/opp
        """
        if context is None:
            context = {}

        if len(ids) <= 1:
            raise osv.except_osv(_('Warning!'), _('Please select more than one element (lead or opportunity) from the list view.'))

        opportunities = self.browse(cr, uid, ids, context=context)
        sequenced_opps = []
        for opportunity in opportunities:
            sequenced_opps.append((opportunity.stage_id and opportunity.stage_id.state != 'cancel' and opportunity.stage_id.sequence or 0, opportunity))
        sequenced_opps.sort(key=lambda tup: tup[0], reverse=True)
        opportunities = [opportunity for sequence, opportunity in sequenced_opps]
        ids = [opportunity.id for opportunity in opportunities]
        highest = opportunities[0]
        opportunities_rest = opportunities[1:]

        tail_opportunities = opportunities_rest

        fields = list(CRM_LEAD_FIELDS_TO_MERGE)
        merged_data = self._merge_data(cr, uid, ids, highest, fields, context=context)

        # Merge messages and attachements into the first opportunity
        self._merge_opportunity_history(cr, uid, highest.id, tail_opportunities, context=context)
        self._merge_opportunity_attachments(cr, uid, highest.id, tail_opportunities, context=context)

        # Merge notifications about loss of information
        opportunities = [highest]
        opportunities.extend(opportunities_rest)
        self._merge_notify(cr, uid, highest, opportunities, context=context)
        # Check if the stage is in the stages of the sales team. If not, assign the stage with the lowest sequence
        if merged_data.get('type') == 'opportunity' and merged_data.get('section_id'):
            section_stages = self.pool.get('crm.case.section').read(cr, uid, merged_data['section_id'], ['stage_ids'], context=context)
            if merged_data.get('stage_id') not in section_stages['stage_ids']:
                stages_sequences = self.pool.get('crm.case.stage').search(cr, uid, [('id','in',section_stages['stage_ids'])], order='sequence', limit=1, context=context)
                merged_data['stage_id'] = stages_sequences[0]
        # Write merged data into first opportunity
        self.write(cr, uid, [highest.id], merged_data, context=context)
        # Delete tail opportunities
        self.unlink(cr, uid, [x.id for x in tail_opportunities], context=context)

        return highest.id

    def _convert_opportunity_data(self, cr, uid, lead, customer, section_id=False, context=None):
        crm_stage = self.pool.get('crm.case.stage')
        contact_id = False
        if customer:
            contact_id = self.pool.get('res.partner').address_get(cr, uid, [customer.id])['default']
        if not section_id:
            section_id = lead.section_id and lead.section_id.id or False
        val = {
            'planned_revenue': lead.planned_revenue,
            'probability': lead.probability,
            'name': lead.name,
            'partner_id': customer and customer.id or False,
            'user_id': (lead.user_id and lead.user_id.id),
            'type': 'opportunity',
            'date_action': fields.datetime.now(),
            'date_open': fields.datetime.now(),
            'email_from': customer and customer.email or lead.email_from,
            'phone': customer and customer.phone or lead.phone,
        }
        if not lead.stage_id or lead.stage_id.type=='lead':
            val['stage_id'] = self.stage_find(cr, uid, [lead], section_id, [('state', '=', 'draft'),('type', 'in', ('opportunity','both'))], context=context)
        return val

    def convert_opportunity(self, cr, uid, ids, partner_id, user_ids=False, section_id=False, context=None):
        customer = False
        if partner_id:
            partner = self.pool.get('res.partner')
            customer = partner.browse(cr, uid, partner_id, context=context)
        for lead in self.browse(cr, uid, ids, context=context):
            if lead.state in ('done', 'cancel'):
                continue
            vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context)
            self.write(cr, uid, [lead.id], vals, context=context)
        self.message_post(cr, uid, ids, body=_("Lead <b>converted into an Opportunity</b>"), subtype="crm.mt_lead_convert_to_opportunity", context=context)

        if user_ids or section_id:
            self.allocate_salesman(cr, uid, ids, user_ids, section_id, context=context)

        return True

    def _lead_create_contact(self, cr, uid, lead, name, is_company, parent_id=False, context=None):
        partner = self.pool.get('res.partner')
        vals = {'name': name,
            'user_id': lead.user_id.id,
            'comment': lead.description,
            'section_id': lead.section_id.id or False,
            'parent_id': parent_id,
            'phone': lead.phone,
            'mobile': lead.mobile,
            'email': lead.email_from and tools.email_split(lead.email_from)[0],
            'fax': lead.fax,
            'title': lead.title and lead.title.id or False,
            'function': lead.function,
            'street': lead.street,
            'street2': lead.street2,
            'zip': lead.zip,
            'city': lead.city,
            'country_id': lead.country_id and lead.country_id.id or False,
            'state_id': lead.state_id and lead.state_id.id or False,
            'is_company': is_company,
            'type': 'contact'
        }
        partner = partner.create(cr, uid, vals, context=context)
        return partner

    def _create_lead_partner(self, cr, uid, lead, context=None):
        partner_id = False
        if lead.partner_name and lead.contact_name:
            partner_id = self._lead_create_contact(cr, uid, lead, lead.partner_name, True, context=context)
            partner_id = self._lead_create_contact(cr, uid, lead, lead.contact_name, False, partner_id, context=context)
        elif lead.partner_name and not lead.contact_name:
            partner_id = self._lead_create_contact(cr, uid, lead, lead.partner_name, True, context=context)
        elif not lead.partner_name and lead.contact_name:
            partner_id = self._lead_create_contact(cr, uid, lead, lead.contact_name, False, context=context)
        elif lead.email_from and self.pool.get('res.partner')._parse_partner_name(lead.email_from, context=context)[0]:
            contact_name = self.pool.get('res.partner')._parse_partner_name(lead.email_from, context=context)[0]
            partner_id = self._lead_create_contact(cr, uid, lead, contact_name, False, context=context)
        else:
            raise osv.except_osv(
                _('Warning!'),
                _('No customer name defined. Please fill one of the following fields: Company Name, Contact Name or Email ("Name <email@address>")')
            )
        return partner_id

    def _lead_set_partner(self, cr, uid, lead, partner_id, context=None):
        """
        Assign a partner to a lead.

        :param object lead: browse record of the lead to process
        :param int partner_id: identifier of the partner to assign
        :return bool: True if the partner has properly been assigned
        """
        res = False
        res_partner = self.pool.get('res.partner')
        if partner_id:
            res_partner.write(cr, uid, partner_id, {'section_id': lead.section_id and lead.section_id.id or False})
            contact_id = res_partner.address_get(cr, uid, [partner_id])['default']
            res = lead.write({'partner_id': partner_id}, context=context)
            message = _("<b>Partner</b> set to <em>%s</em>." % (lead.partner_id.name))
            self.message_post(cr, uid, [lead.id], body=message, context=context)
        return res

    def handle_partner_assignation(self, cr, uid, ids, action='create', partner_id=False, context=None):
        """
        Handle partner assignation during a lead conversion.
        if action is 'create', create new partner with contact and assign lead to new partner_id.
        otherwise assign lead to the specified partner_id

        :param list ids: leads/opportunities ids to process
        :param string action: what has to be done regarding partners (create it, assign an existing one, or nothing)
        :param int partner_id: partner to assign if any
        :return dict: dictionary organized as followed: {lead_id: partner_assigned_id}
        """
        #TODO this is a duplication of the handle_partner_assignation method of crm_phonecall
        partner_ids = {}
        # If a partner_id is given, force this partner for all elements
        force_partner_id = partner_id
        for lead in self.browse(cr, uid, ids, context=context):
            # If the action is set to 'create' and no partner_id is set, create a new one
            if action == 'create':
                partner_id = force_partner_id or self._create_lead_partner(cr, uid, lead, context)
            self._lead_set_partner(cr, uid, lead, partner_id, context=context)
            partner_ids[lead.id] = partner_id
        return partner_ids

    def allocate_salesman(self, cr, uid, ids, user_ids=None, team_id=False, context=None):
        """
        Assign salesmen and salesteam to a batch of leads.  If there are more
        leads than salesmen, these salesmen will be assigned in round-robin.
        E.g.: 4 salesmen (S1, S2, S3, S4) for 6 leads (L1, L2, ... L6).  They
        will be assigned as followed: L1 - S1, L2 - S2, L3 - S3, L4 - S4,
        L5 - S1, L6 - S2.

        :param list ids: leads/opportunities ids to process
        :param list user_ids: salesmen to assign
        :param int team_id: salesteam to assign
        :return bool
        """
        index = 0

        for lead_id in ids:
            value = {}
            if team_id:
                value['section_id'] = team_id
            if user_ids:
                value['user_id'] = user_ids[index]
                # Cycle through user_ids
                index = (index + 1) % len(user_ids)
            if value:
                self.write(cr, uid, [lead_id], value, context=context)
        return True

    def schedule_phonecall(self, cr, uid, ids, schedule_time, call_summary, desc, phone, contact_name, user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
        """
        :param string action: ('schedule','Schedule a call'), ('log','Log a call')
        """
        phonecall = self.pool.get('crm.phonecall')
        model_data = self.pool.get('ir.model.data')
        phonecall_dict = {}
        if not categ_id:
            res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
            if res_id:
                categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
        for lead in self.browse(cr, uid, ids, context=context):
            if not section_id:
                section_id = lead.section_id and lead.section_id.id or False
            if not user_id:
                user_id = lead.user_id and lead.user_id.id or False
            vals = {
                'name': call_summary,
                'opportunity_id': lead.id,
                'user_id': user_id or False,
                'categ_id': categ_id or False,
                'description': desc or '',
                'date': schedule_time,
                'section_id': section_id or False,
                'partner_id': lead.partner_id and lead.partner_id.id or False,
                'partner_phone': phone or lead.phone or (lead.partner_id and lead.partner_id.phone or False),
                'partner_mobile': lead.partner_id and lead.partner_id.mobile or False,
                'priority': lead.priority,
            }
            new_id = phonecall.create(cr, uid, vals, context=context)
            phonecall.case_open(cr, uid, [new_id], context=context)
            if action == 'log':
                phonecall.case_close(cr, uid, [new_id], context=context)
            phonecall_dict[lead.id] = new_id
            self.schedule_phonecall_send_note(cr, uid, [lead.id], new_id, action, context=context)
        return phonecall_dict

    def redirect_opportunity_view(self, cr, uid, opportunity_id, context=None):
        models_data = self.pool.get('ir.model.data')

        # Get opportunity views
        dummy, form_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
        dummy, tree_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_tree_view_oppor')
        return {
            'name': _('Opportunity'),
            'view_type': 'form',
            'view_mode': 'tree, form',
            'res_model': 'crm.lead',
            'domain': [('type', '=', 'opportunity')],
            'res_id': int(opportunity_id),
            'view_id': False,
            'views': [(form_view or False, 'form'),
                    (tree_view or False, 'tree'),
                    (False, 'calendar'), (False, 'graph')],
            'type': 'ir.actions.act_window',
        }

    def redirect_lead_view(self, cr, uid, lead_id, context=None):
        models_data = self.pool.get('ir.model.data')

        # Get lead views
        dummy, form_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_form_view_leads')
        dummy, tree_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_tree_view_leads')
        return {
            'name': _('Lead'),
            'view_type': 'form',
            'view_mode': 'tree, form',
            'res_model': 'crm.lead',
            'domain': [('type', '=', 'lead')],
            'res_id': int(lead_id),
            'view_id': False,
            'views': [(form_view or False, 'form'),
                      (tree_view or False, 'tree'),
                      (False, 'calendar'), (False, 'graph')],
            'type': 'ir.actions.act_window',
        }

    def action_makeMeeting(self, cr, uid, ids, context=None):
        """
        Open meeting's calendar view to schedule meeting on current opportunity.
        :return dict: dictionary value for created Meeting view
        """
        opportunity = self.browse(cr, uid, ids[0], context)
        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'base_calendar', 'action_crm_meeting', context)
        res['context'] = {
            'default_opportunity_id': opportunity.id,
            'default_partner_id': opportunity.partner_id and opportunity.partner_id.id or False,
            'default_partner_ids' : opportunity.partner_id and [opportunity.partner_id.id] or False,
            'default_user_id': uid,
            'default_section_id': opportunity.section_id and opportunity.section_id.id or False,
            'default_email_from': opportunity.email_from,
            'default_name': opportunity.name,
        }
        return res

    def write(self, cr, uid, ids, vals, context=None):
        if vals.get('stage_id') and not vals.get('probability'):
            # change probability of lead(s) if required by stage
            stage = self.pool.get('crm.case.stage').browse(cr, uid, vals['stage_id'], context=context)
            if stage.on_change:
                vals['probability'] = stage.probability
        return super(crm_lead, self).write(cr, uid, ids, vals, context=context)

    def new_mail_send(self, cr, uid, ids, context=None):
        '''
        This function opens a window to compose an email, with the edi sale template message loaded by default
        '''
        assert len(ids) == 1, 'This option should only be used for a single id at a time.'
        ir_model_data = self.pool.get('ir.model.data')
        try:
            template_id = ir_model_data.get_object_reference(cr, uid, 'crm', 'email_template_opportunity_mail')[1]
        except ValueError:
            template_id = False
        try:
            compose_form_id = ir_model_data.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form')[1]
        except ValueError:
            compose_form_id = False 
        if context is None:
            context = {}
        ctx = context.copy()
        ctx.update({
            'default_model': 'crm.lead',
            'default_res_id': ids[0],
            'default_use_template': bool(template_id),
            'default_template_id': template_id,
            'default_composition_mode': 'comment',
        })
        return {
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'mail.compose.message',
            'views': [(compose_form_id, 'form')],
            'view_id': compose_form_id,
            'target': 'new',
            'context': ctx,
        }

    # ----------------------------------------
    # Mail Gateway
    # ----------------------------------------

    def message_get_reply_to(self, cr, uid, ids, context=None):
        """ Override to get the reply_to of the parent project. """
        return [lead.section_id.message_get_reply_to()[0] if lead.section_id else False
                    for lead in self.browse(cr, uid, ids, context=context)]

    def message_new(self, cr, uid, msg, custom_values=None, context=None):
        """ Overrides mail_thread message_new that is called by the mailgateway
            through message_process.
            This override updates the document according to the email.
        """
        if custom_values is None: custom_values = {}

        desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
        defaults = {
            'name':  msg.get('subject') or _("No Subject"),
            'description': desc,
            'email_from': msg.get('from'),
            'email_cc': msg.get('cc'),
            'partner_id': msg.get('author_id', False),
            'user_id': False,
        }
        if msg.get('author_id'):
            defaults.update(self.on_change_partner(cr, uid, None, msg.get('author_id'), context=context)['value'])
        if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
            defaults['priority'] = msg.get('priority')
        defaults.update(custom_values)
        return super(crm_lead, self).message_new(cr, uid, msg, custom_values=defaults, context=context)

    def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
        """ Overrides mail_thread message_update that is called by the mailgateway
            through message_process.
            This method updates the document according to the email.
        """
        if isinstance(ids, (str, int, long)):
            ids = [ids]
        if update_vals is None: update_vals = {}

        if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES):
            update_vals['priority'] = msg.get('priority')
        maps = {
            'cost':'planned_cost',
            'revenue': 'planned_revenue',
            'probability':'probability',
        }
        for line in msg.get('body', '').split('\n'):
            line = line.strip()
            res = tools.command_re.match(line)
            if res and maps.get(res.group(1).lower()):
                key = maps.get(res.group(1).lower())
                update_vals[key] = res.group(2).lower()

        return super(crm_lead, self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)

    # ----------------------------------------
    # OpenChatter methods and notifications
    # ----------------------------------------

    def schedule_phonecall_send_note(self, cr, uid, ids, phonecall_id, action, context=None):
        phonecall = self.pool.get('crm.phonecall').browse(cr, uid, [phonecall_id], context=context)[0]
        if action == 'log': prefix = 'Logged'
        else: prefix = 'Scheduled'
        message = _("<b>%s a call</b> for the <em>%s</em>.") % (prefix, phonecall.date)
        return self.message_post(cr, uid, ids, body=message, context=context)

    def onchange_state(self, cr, uid, ids, state_id, context=None):
        if state_id:
            country_id=self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id
            return {'value':{'country_id':country_id}}
        return {}
class stock_partial_picking_line(orm.TransientModel):
    _inherit = "stock.partial.picking.line"

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

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

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

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

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

        return True

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

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

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

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

    def onchange_new_prodlot_code(self, cr, uid, ids, new_prodlot_code, product_id, prodlot_id, context=None):
        lot_obj = self.pool['stock.production.lot']
        if new_prodlot_code:
            new_prodlot_code = new_prodlot_code.upper()  # all serial number must be on uppercase
        existing_prodlot_ids = lot_obj.search(cr, uid, [('name', '=', new_prodlot_code), ('product_id', '=', product_id)], limit=1, context=context)
        existing_lot = lot_obj.browse(cr, uid, existing_prodlot_ids, context)
        move_type = self.pool['stock.partial.picking.line'].browse(cr, uid, ids, context=context)[0].move_id.picking_id.type
        if existing_lot:
            product = self.pool['product.product'].browse(cr, uid, product_id, context=context)
            if product.lot_split_type == 'single' and move_type != 'out' and existing_lot[0].stock_available > 0:
                return {
                    'warning': {
                        'title': _('Warning!'),
                        'message': (_('Serial number "{number}" is already exists').format(number=new_prodlot_code))
                    }
                }
            else:
                existing_lot_id = existing_prodlot_ids[0]
                return {'value': {'prodlot_id': existing_lot_id}}
        else:
            prodlot_id = self.pool['stock.production.lot'].create(cr, uid, {
                'name': new_prodlot_code,
                'product_id': product_id,
            })
            return {'value': {'prodlot_id': prodlot_id}}
Example #43
0
        'cc_state':fields.char('State', size=32,),
        'cc_zip':fields.char('Postal/Zip', size=32,),
        'cc_country':fields.char('Country', size=32,),
        'cc_order_date':fields.date('Order Date',),
<<<<<<< HEAD
        'cc_order_amt':fields.float('Order Amt'),
=======
        'cc_order_amt':fields.float('Order Amt',required=True),
>>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d
        'cc_number':fields.char('Credit Card Number', size=256),
        'cc_v':fields.char('Card Code Verification', size=3),
        'cc_e_d_month':fields.char('Expiration Date MM', size=32),
        'cc_e_d_year':fields.char('Expiration Date YY', size=32),
        'cc_comment':fields.char('Comment', size=128,),
        'cc_auth_code':fields.char('Authorization Code', size=32),
        'cc_save_card_details':fields.boolean('Save Credit Card details'),
        'cc_ecommerce_sale':fields.boolean('Ecommerce sale'),
        'cc_p_authorize':fields.boolean('Pre-authorize'),
        'cc_charge':fields.boolean('Charge'),
        'cc_info_hide':fields.boolean('Credit Info Hide'),
        'cc_status':fields.text('Status Message'),
        'cc_details_autofill':fields.boolean('Credit Card Details Auto Fill'),
        'cc_reseller':fields.boolean('Reseller'),
        'rel_sale_order_id':fields.many2one('sale.order', 'Related Sale Order'),
        'cc_trans_id':fields.char('Transaction ID', size=128),
        'cc_bank':fields.many2one('res.bank', 'Bank'),
        'cc_details':fields.many2one('res.partner.bank', 'Bank'),
        'cc_length':fields.integer('CC Length'),
        'cc_transaction':fields.boolean('Transaction Done'),
        'key':fields.char('Encryption Key', size=1024,
                          help="The Key used to Encrypt the Credit Card Number"),
Example #44
0
class openacademy_session(osv.Model):
    _name = 'openacademy.session'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    _constraints = [(_check_instructor_not_in_attendees,
                     "El instructor no puede ser asistente",
                     ['instructor_id', 'attendee_ids'])]
Example #45
0
            res[company.id]['smart_budget'] = round(res[company.id]['smart_budget']  - res[company.id]['smart_amount_budget'],0)

            
                 
            #res[company.id]['smart_cash'] = 0.0
        return res

    _columns = {
       'smart_budget': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Budget',multi='all',help="Approved invoiced amount.",),
#       'smart_cash': fields.function(smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Budget',
#            help="Approved invoiced amount.",
#            multi='all',),
       'smart_cash': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Cash',
            help="Free invoiced amount for salary or expenses.",
            multi='all',),
        'prepayment': fields.boolean('Prepayment',help="SMart User: this virtual company can have prepayment smart_cash, SMart Company: this country applies prepayment"),
        'prepayment_days': fields.integer('Prepayment Days',help="Leadtime in days before invoiced amount becomes smart_cash (global)"),
        'smart_share': fields.float('SMarts Share',digits_compute=dp.get_precision('Account')),
        'sale_order_sum_cash': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Order sum cash',multi='all',help="Approved invoiced amount.",),
        'sale_order_sum_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Order sum budget',multi='all',help="Approved invoiced amount.",),
        'smart_amount_cash':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Amount cash',multi='all',help="Approved invoiced amount.",),
        'smart_amount_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Amount budget',multi='all',help="Approved invoiced amount.",),
        'activity_amount_cash':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart activity amount cash',multi='all',help="Approved invoiced amount.",),
        'activity_amount_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart activity amount budget',multi='all',help="Approved invoiced amount.",),
        'expense_sum_cash':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart expense sum cash',multi='all',help="Approved invoiced amount.",),
        'expense_sum_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart expense sum budget',multi='all',help="Approved invoiced amount.",),
    }

    _defaults = {
        'prepayment': True,
        'smart_cash': 0.0,
Example #46
0
class EdiHistoryCheck(osv.osv):
    ''' Manage path for all company EDI that has active routes
    '''
    
    _name = 'edi.history.check'
    _description = 'EDI history check'
    _order = 'name,sequence,line_out,line_in'
    
    # ----------------------------
    # Button and utility function:
    # ----------------------------
    def dummy_button(self, cr, uid, ids, context=None):
        ''' Button does nothing
        '''
        return True

    # Button OUT block:
    def button_header_out(self, cr, uid, ids, context=None):
        return self.get_order_out(cr, uid, ids, 'header', context=context)

    def button_detail_out(self, cr, uid, ids, context=None):
        return self.get_order_out(cr, uid, ids, 'detail', context=context)
                
    def button_document_out(self, cr, uid, ids, context=None):
        return self.get_order_out(cr, uid, ids, 'account', context=context)

    def get_order_out(self, cr, uid, ids, button_mode='header', context=None):
        ''' Open view for see all order OUT
            button_mode for choose the type of filter: 
                'header', 'detail', 'account'
        '''
        order_proxy = self.browse(cr, uid, ids, context=context)[0]
        
        if button_mode == 'header':
            domain = [('name', '=', order_proxy.name)]
        elif button_mode == 'detail':   
            domain = [('name', '=', order_proxy.name_detail)]
        elif button_mode == 'account':
            domain = [('document_out', '=', order_proxy.document_out)]
        else:
            raise osv.except_osv(
                _('Error!'), 
                _('Buttot filter not found!'),
                )

        context['search_default_order_state_urgent_grouped'] = False
        return {
            'res_model': 'edi.history.check',
            'type': 'ir.actions.act_window',
            'target': 'new',
            'view_type': 'form',
            'view_mode': 'tree,form',
            #'res_id': context.get('active_id', False),
            'context': None,
            'domain': domain, 
            }

    # Button IN block:
    def button_header_in(self, cr, uid, ids, context=None):
        return self.get_order_in(cr, uid, ids, 'header', context=context)

    def button_detail_in(self, cr, uid, ids, context=None):
        return self.get_order_in(cr, uid, ids, 'detail', context=context)

        
    def get_order_in(self, cr, uid, ids, button_mode='header', context=None):
        ''' Open view for see all order IN
            context for pass button_mode: 'header' (def.), 'detail'
        '''
        # Search header or detail order code
        order_proxy = self.browse(cr, uid, ids, context=context)[0]
        order_pool = self.pool.get('edi.history.order')
        
        if button_mode == 'header':
            order = _('Order header IN: %s') % order_proxy.name
            domain = [('name', '=', order_proxy.name)]
        else:
            order = _('Order detail IN: %s') % order_proxy.name_detail
            domain = [('name', '=', order_proxy.name_detail)]

        order_ids = order_pool.search(cr, uid, domain, context=context)
        if order_ids:            
            return {
                'res_model': 'edi.history.order',
                'type': 'ir.actions.act_window',
                'target': 'new',
                'view_type': 'form',
                'view_mode': 'form',
                'res_id': order_ids[0],
                'context': {
                    'search_default_order_state_urgent_grouped': False},
                'domain': [('name', '=', order_ids[0])], 
                }

        raise osv.except_osv(
            _('Error!'), 
            _('Order not found in archive: %s' % order),
            )
        
    # -------------------------------------------------------------------------
    #                             Scheduled action
    # -------------------------------------------------------------------------
    def import_invoce_check(self, cr, uid, code, context=None):
        ''' Import procedure for check if order are correctly imported and 
            match with invoice / delivery document in account
            self: instance object
            cr: cursor for database
            uid: user ID
            context: parameter arguments passed
        '''
        # TODO code will be list if used in other company

        # ---------------------------------------------------------------------
        #                            Utility function
        # ---------------------------------------------------------------------
        def update_dict_with_parent_product(self, cr, uid, 
                parent_product, parent_code, context=None):
            ''' Search parent code in dict if not present create and update
                dictionary (used this for external search)
                (ID, quantity tolerance, price tolerance)
            '''
            parent_pool = self.pool.get('edi.product.parent')
            if parent_code not in parent_product:
                parent_product[parent_code] = (
                    parent_pool.create(cr, uid, {
                        'code': parent_code,
                        'name': _('Product parent code %s') % parent_code,
                        }, context=context),
                    5.0, # quantity_tolerance     
                    5.0, # price_tolerance     
                    )
            else: 
                parent_ids = parent_pool.search(cr, uid, [
                    ('code', '=', parent_code)], context=context)
                # parent_ids must exist (parent_product loaded with it
                parent_proxy = parent_pool.browse(
                    cr, uid, parent_ids, context=context)[0]
                parent_product[parent_code] = (
                    parent_proxy.id,
                    parent_proxy.quantity_tolerance,
                    parent_proxy.price_tolerance,
                    )
            return        
            
        def remove_from_list(order_in_check, order, line):
            ''' Remove without error
            '''
            try: 
                order_in_check.remove((order, line_out)) # error if not present
            except:
                pass # no problem on error
            return
            
        def sort_sequence(filelist):
            ''' Internal utility for sort list get priority to orders and
                then to ordchg after to normal order
            '''
            # TODO add some controls (need to be right)
            
            # Split in 2 list the element depend on type:
            if len(filelist) in (0, 1): # 0 raise error?
                return filelist
                
            orders = sorted([
                filename for filename in filelist if 'ORDERS' in filename])
            if len(orders) > 1:
                _logger.error('More than one ORDERS file %s' % orders )    
                # TODO what to do now?

            ordchg = sorted([
                filename for filename in filelist if 'ORDCHG' in filename])
            
            # order and merge as is:    
            orders.extend(ordchg)
            return orders
            
        def load_order_from_history(order, history_filename, order_record, 
                order_in_check):
            ''' Function that load all files and create a dictionary with row
                key
                The function also save in database the order for a readable 
                check in.
                
                order: order code origin
                history_filename: database of filename (list for every order)
                order_record: dict with order line imported from history files
                order_in_check: list of all record (for set order_in attribute)
            '''     
            
            if order in order_record: # pass only the first time
                return 

            modified = False            
            order_record[order] = {}

            sort_history_filename = sort_sequence(
                history_filename.get(order, []))
            for filename in sort_history_filename:
                # Read all files and update dict with row record:
                f = open(filename)
                m_time = time.ctime(os.path.getmtime(filename))
                c_time = time.ctime(os.path.getctime(filename))
                for row in f:
                    file_type = row[10:16] # ORDERS or ORDCHG
                    update_type = row[16:19] # 003 ann, 001 mod. q.
                    line_in = row[2336:2341] # 5
                    article = row[2356:2367].strip() # 11
                    quantity = float(row[2631:2641].strip() or '0')
                    price = float(row[2964:2994].strip() or '0')

                    if file_type == 'ORDERS':
                        line_type = 'original'
                    else: # ORDCHG
                        modified = True
                        if update_type == '001':
                            line_type = 'update' 
                        elif update_type == '003':    
                            line_type = 'cancel'
                        else: # operation non in list
                            _logger.error(
                                'Update code not found: %s' % update_type)
                            line_type = 'error'                    
                    order_record[order][line_in] = (
                        # For check with account information:
                        article, line_type, quantity, price, 
                        
                        # For history record file in database:
                        filename, c_time, m_time)
                    
                    if (order, line_in) not in order_in_check: # for modify!
                        order_in_check.append(
                            (order, line_in)) # add key for test A - B 
                    
            # Save file for create a HTML order more readable:                          
            if order: # jump empty
                order_html = _('''
                    <style>
                        .table_bf {
                             border: 1px solid black;
                             padding: 3px;
                             }                             
                        .table_bf td {
                             border: 1px solid black;
                             padding: 3px;
                             text-align: center;
                             }
                        .table_bf_wo td {
                             border: 1px solid black;
                             padding: 3px;
                             text-align: center;
                             background-color: AntiqueWhite;
                             text-decoration: line-through;
                             }                             
                        .table_bf_upd td {
                             border: 1px solid black;
                             padding: 3px;
                             text-align: center;
                             background-color: Gainsboro;
                             }                             
                        .table_bf th {
                             border: 1px solid black;
                             padding: 3px;
                             text-align: center;
                             background-color: grey;
                             color: white;
                             }
                    </style>

                    <table class='table_bf'>
                        <tr class='table_bf'>
                            <th>Line</th><th>Article</th><th>Quant.</th>
                            <th>Price</th><th>File</th><th>Create</th>
                            <th>Mod.</th>
                        </tr>''')
                
                for line_in in sorted(order_record[order].keys()):
                    # Chose color line with class:
                    if order_record[order][line_in][1] == 'cancel':
                        row_class = 'class="table_bf_wo"'
                    elif order_record[order][line_in][1] == 'update':
                        row_class = 'class="table_bf_upd"'
                    else:
                        row_class = ''    
                    
                    order_html += '''
                        <tr %s>
                            <td>%s</td><td>%s</td><td>%s</td>
                            <td class='{text-align: right;}'>%s</td>
                            <td class='{text-align: right;}'>%s</td>
                            <td>%s</td><td>%s</td>
                        </tr>
                        ''' % (
                            row_class, # Cancel state
                            line_in, # Row
                            order_record[order][line_in][0], # Article
                            order_record[order][line_in][2], # Quant.
                            order_record[order][line_in][3], # Price
                            # Filename (base name extract from full path:
                            os.path.basename(order_record[order][line_in][4]),                             
                            order_record[order][line_in][5], # Create date
                            order_record[order][line_in][6], # Modifty date
                            )
                order_html += '</table>'    
                            
                order_pool = self.pool.get('edi.history.order')
                order_ids = order_pool.search(cr, uid, [
                    ('name', '=', order)], context=context)
                # Create file list:
                file_list = ""
                for f in sort_history_filename:
                    file_list += "%s\n" % os.path.basename(f)
                if order_ids: 
                    order_id = order_ids[0]    
                    order_pool.write(cr, uid, order_id, {
                        'note': order_html,
                        'modified': modified,
                        'file': file_list, 
                        'total': len(sort_history_filename),
                        }, context=context)    
                else:
                    order_id = order_pool.create(cr, uid, {
                        'name': order,
                        'modified': modified,
                        'note': order_html,
                        'file': file_list,
                        'total': len(sort_history_filename),
                        }, context=context)    
                         
            return # TODO order_id?
            
        # ---------------------------------------------------------------------
        #        Start procedure and get configuration parameters
        # ---------------------------------------------------------------------
        _logger.info('Start import history order for check')
        
        # --------------------------
        # Read configuration record:
        # --------------------------
        # Read record for code passed in scheduling:
        config_pool = self.pool.get('edi.history.configuration')
        config_ids = config_pool.search(cr, uid, [
            ('code', '=', code)], context=context)
        if not config_ids:    
            _logger.error('Code %s not found in configuration file!' % code)
            return False
        config_proxy = config_pool.browse(
            cr, uid, config_ids, context=context)[0]
            
        # Folder path:    
        input_folder = config_proxy.history_path # history order
        input_invoice = config_proxy.invoice_file # account invoice
        
        # Precision for price / quantity evaluation
        quant_prec = config_proxy.quantity_precision
        price_prec = config_proxy.price_precision

        # ---------------
        # Clean database:
        # ---------------
        remove_ids = self.search(cr, uid, [], context=context)
        self.unlink(cr, uid, remove_ids, context=context)

        # -------------------
        # Read files history:
        # -------------------
        # Save in dict for future access (that parse whole order and modify)
        history_filename = {} # list of file (key=order, value=filename)
        order_record = {} # record in file (k order, v {row: (art, state)}
        order_in_check = []
        for root, directories, files in os.walk(input_folder):
            for filename in files:                
                filepath = os.path.join(root, filename)
                f = open(filepath, 'rb')
                row = f.read()
                f.close()
                order = row[19:29].strip()
                if not order:
                    _logger.error(
                        'Found order without name (jump): %s' % filename)
                    continue
                if order not in history_filename:
                    history_filename[order] = [] # Create empty list
                #os.path.getmtime(filepath) # TODO for evaluation order prior.
                history_filename[order].append(filepath)

        # -------------------------
        # Load parent product code:
        # -------------------------
        parent_product = {}
        parent_pool = self.pool.get('edi.product.parent')
        parent_ids = parent_pool.search(cr, uid, [], context=context)
        for c in parent_pool.browse(cr, uid, parent_ids, context=context):
            parent_product[c.code] = (
                c.id, c.quantity_tolerance, c.price_tolerance)
        
        # ---------------------
        # Start import invoice:
        # ---------------------
        # Read all lines and save only duplicated
        order_out_check = [] # List of order-row for check duplication
        i = -config_proxy.header
        sequence = 0
        
        old_order = False
        old_line = False
        
        # TODO problem with order (not sorted with invoice/ddt)
        for invoice in csv.reader(
                open(input_invoice, 'rb'), 
                delimiter=str(config_proxy.delimiter)):
            i += 1
            sequence += 1
            if i <= 0:
                _logger.info('Jump header lines')
                continue

            # Mapping fields:
            doc_type = invoice[0].strip()
            document_out = invoice[1].strip()
            order = invoice[2].strip() # header
            article = invoice[3].strip()
            order_detail = invoice[4].strip()
            line_out = invoice[5].strip()            
            quantity = float(invoice[6].strip().replace(',', '.') or '0')
            price = float(invoice[7].strip().replace(',', '.') or '0')
            # TODO check alias article for get correct element
            
            update_dict_with_parent_product(self, cr, uid, 
                parent_product, article[:3], context=context)
            
            data = {
                'sequence': sequence, # for sort as account (check seq. err.)
                'name': order, # to search in history
                'name_detail': order_detail,
                'line_in': False,
                'line_out': line_out,
                
                'quantity_in': False,
                'quantity_out': quantity,
                'over_quantity': False,

                'price_in': False,
                'price_out': price,                
                'over_price': False,

                'document_out': document_out,
                'document_type': doc_type,

                'product_code_in': False,
                'parent_in_id': False,
                #'product_parent_in': False,

                'product_code_out': article,
                'parent_out_id': parent_product.get(article[:3], (
                    False, 0.0, 0.0))[0],
                #'product_parent_out': article[:3],
                }

            # -------------------------------
            # STATE MANAGE: Speed check case:
            # -------------------------------
            if not order:
                if not order_detail:
                    data['name'] = _('NOT FOUND!')
                    data['state'] = 'no_order'
                    self.create(cr, uid, data, context=context)
                    continue
                data['use_detail_order'] = True
                order = order_detail                    
                data['name'] = order
            elif order != order_detail:
                data['state'] = 'order'
                self.create(cr, uid, data, context=context)
                continue

            data['state'] = 'ok' # temporary OK after account check

            # Load order if not present in database:
            if order not in order_record:
                load_order_from_history(
                    order, history_filename, order_record, order_in_check)
            
            # -----------------------------
            # STATE MANAGE: Duplicated row:
            # -----------------------------
            if (order, line_out) in order_out_check:
                # if duplicated was yet removed from order_in_check
                data['state'] = 'duplicated'
                self.create(cr, uid, data, context=context)
                continue # Jump line

            order_out_check.append((order, line_out)) # used for check dupl.

            # -----------------------------
            # STATE MANAGE: Sequence error:
            # -----------------------------
            wrong_sequence = False
            # Note: sequence is evaluated here for "old" counter but,
            # if present, the write operation is done after wrong_line & only 
            # out, this because are more important than sequence error
            if old_order == (order, document_out):
                # NOTE: Break the sequence with order and invoice!!!
                if old_line and line_out < old_line:
                    old_line = line_out
                    data['state'] = 'sequence'
                    wrong_sequence = True 
                else:
                    old_line = line_out # No error, save this as old
            else: # If change order reset line:
                old_order = (order, document_out)
                old_line = line_out # first line of order

            # ---------------------------------------------------
            # HISTORY ANALYSIS: Wrong line (not present in order)
            # ---------------------------------------------------
            # NOTE: More important than sequence!!
            if line_out not in order_record[order]: # (article, line_type)
                data['state'] = 'wrong_line' # not presen in order
                self.create(cr, uid, data, context=context)
                continue # Jump line


            # Remove here line for only_in test (so out removed from in)
            remove_from_list(order_in_check, order, line_out) 
            
            # ---------------------------------------------------------------
            # HISTORY ANALYSIS: Line removed (present in order but cancelled)
            # ---------------------------------------------------------------
            if order_record[order][line_out][1] == 'cancel':
                data['state'] = 'only_out' # present but deleted in order                
                self.create(cr, uid, data, context=context)
                continue # Jump line

            # Note: Here we write wrong sequence, before valuated, if present:
            if wrong_sequence:
                self.create(cr, uid, data, context=context)
                continue

            # ------------------------------------------
            # HISTORY ANALYSIS: Test article is the same
            # ------------------------------------------
            data['product_code_in'] = order_record[order][line_out][0]
            update_dict_with_parent_product(self, cr, uid, 
                parent_product, order_record[order][line_out][0][:3], 
                context=context)
            data['parent_in_id'] = parent_product.get(
                order_record[order][line_out][0][:3], (False, 0.0, 0.0))[0]
                
            if order_record[order][line_out][0] != article[:11]:
                data['line_in'] = line_out
                data['state'] = 'article'
                self.create(cr, uid, data, context=context)
                continue # Jump line
                
                
            # ------------------------------------------------
            # HISTORY ANALYSIS: Warning test for q. and price:
            # ------------------------------------------------
            # Price in % of tolerance
            data['price_in'] = order_record[order][line_out][3] # 4 element
            price_tolerance = parent_product.get(
                order_record[order][line_out][0][:3], (False, 0.0, 0.0))[2]
            if data['price_in'] and 100.0 / data['price_in'] * abs(
                    data['price_in'] - price) > price_tolerance:
                data['over_price'] = True

            # Quantity in % of tolerance
            data['quantity_in'] = order_record[order][line_out][2] # 3 element
            quantity_tolerance = parent_product.get(
                order_record[order][line_out][0][:3], (False, 0.0, 0.0))[1]
            if data['quantity_in'] and 100.0 / data['quantity_in'] * abs(
                    data['quantity_in'] - quantity) > quantity_tolerance:
                data['over_quantity'] = True
            
            # ----------------------------------------
            # HISTORY ANALYSIS: Test price is the same
            # ----------------------------------------
            if abs(data['price_in'] - price) > price_prec:
                data['line_in'] = line_out
                #data['quantity_in'] = False # raise price error, q restore 0.0
                data['state'] = 'price'
                self.create(cr, uid, data, context=context)
                continue # Jump line
            
            # -------------------------------------------
            # HISTORY ANALYSIS: Test quantity is the same
            # -------------------------------------------
            if abs(data['quantity_in'] - quantity) > quant_prec:
                data['line_in'] = line_out
                data['state'] = 'quantity'
                self.create(cr, uid, data, context=context)
                continue # Jump line

            # ----------------------------
            # CORRECT RECORD: Save article
            # ----------------------------
            # Note: line_in now are equals to line_out!
            data['line_in'] = line_out # must to be here (after all)
            self.create(cr, uid, data, context=context)
        
        # Write line present in IN and not in OUT:
        # Note: must be before mark order evaluation!
        order_yet_found = []
        for (order, line_in) in order_in_check:
            if order not in order_record:
                _logger.error(
                    'Order %s with in line not found not present!' % order)
                continue    

            order_in = order_record[order] # yet loaded master loop        
            # Create line for order in without order out fields:

            # TODO put in function:
            update_dict_with_parent_product(self, cr, uid, 
                parent_product, order_in[line_in][0][:3], context=context)

            data = {
                'sequence': 0, # first line not prest in order out
                'name': order,
                'name_detail': False,
                'line_in': line_in, # Use line_out
                'line_out': False,
                'quantity_in': order_in[line_in][2],
                'quantity_out': False,
                'price_in': order_in[line_in][3],
                'price_out': False,                
                'document_out': False,
                'document_type': False,
                'state': 'only_in',
                
                # Product and parent:
                'product_code_in': order_in[line_in][0],
                'parent_in_id': parent_product.get(
                    order_in[line_in][0][:3], (False, 0.0, 0.0))[0],
                #'product_parent_in': order_in[line_in][0][:3], # TODO remove
                
                'product_code_out': False,
                'parent_out_id': False,
                #'product_parent_out': False, # TODO remove
                }
            self.create(cr, uid, data, context=context)
            if order not in order_yet_found: # write only once
                _logger.warning('Order with only_in case: %s' % order)
                order_yet_found.append(order)

        # -------------------------------------------
        # Update field for show all order with errors
        # -------------------------------------------
        # Mark all order as error where there's almost one line (after all!)
        
        # NOTE: Splitted in two, maybe for precedence problems
        _logger.info('Mark all order error if has line problem:')
                
        line_ko_ids = self.search(cr, uid, [ # Line with problems
            ('state', '!=', 'ok'), # OK
            ('state', '!=', 'quantity'), # No order error if quantity
            ], context=context)            

        order_ko_list = [ # Order code list:    
            item.name for item in self.browse(
                cr, uid, line_ko_ids, context=context)]
                
        order_ko_ids = self.search(cr, uid, [ # All order lines:    
            ('name', 'in', order_ko_list), ], context=context)
        
        self.write(cr, uid, order_ko_ids, { # Upd. field for search whole order
            'order_error': True
            }, context=context)

        return True
    
    _columns = {
        'sequence': fields.integer('Sequence'),

        'name': fields.char('Order name', size=25, 
            help='Order ID of company'),
        'name_detail': fields.char('Order detail', size=25, 
            help='Order ID in accounting detail'),
        
        'price_in': fields.float('Price in', digits=(16, 2)), 
        'price_out': fields.float('Price out', digits=(16, 2)), 
        'over_price': fields.boolean('Over price'),

        'quantity_in': fields.float('Quantity in', digits=(16, 2)), 
        'quantity_out': fields.float('Quantity out', digits=(16, 2)), 
        'over_quantity': fields.boolean('Over quantity'),

        'line_in': fields.char('Line in', size=5, help='Order line'),
        'line_out': fields.char('Line out', size=5, 
            help='Delivery of invoice line'),

        'product_code_in': fields.char('Product in', size=18, 
            help='Order product in'),
        'product_code_out': fields.char('Product out', size=18, 
            help='Invoice or delivery product out'),

        'parent_in_id': fields.many2one('edi.product.parent', 'Parent IN', 
            help='Parent ID code (order in product)'),
        'parent_out_id': fields.many2one('edi.product.parent', 'Parent OUT', 
            help='Parent ID code (document out accounting product)'),

        'document_out': fields.char('Document out', size=20,
            help='Number of document, delivery or invoice, out'),
        'document_type': fields.selection([
            ('OC', 'Order'),
            ('BC', 'Document of transport'),
            ('FT', 'Invoice'),
            ], 'Document type', help='Document out type'),

        'order_error': fields.boolean('Order error', 
            help='As if the line is correct in order there\'s almost one line'
                'with error'),
        'use_detail_order': fields.boolean('Use detail order', 
            help='This line don''t have order so used detail'),

        'state': fields.selection([
            # First control, readind account file:
            ('no_order', 'Order not present'),
            ('order', 'Order doesn\'t match'),
            ('sequence', 'Sequence error'),
            ('duplicated', 'Row duplicated'),
            
            # Control reading history:
            ('only_in', 'Not imported'), # not present in accounting
            ('only_out', 'Extra line'), # only out (order was cancel)
            ('wrong_line', 'Wrong line'), # not present in order
            ('article', 'Article error'),
            ('quantity', 'Quantity error'), # TODO Manage
            ('price', 'Price error'), # TODO 
            ('unmanaged', 'Error unmanaged'),
            
            # If all correct:
            ('ok', 'Correct'),
            ], 'State', help='Error state'),            
        }
class stock_fill_inventory(osv.osv_memory):
    _inherit = "stock.fill.inventory"

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

    _columns = {
        'set_account_zero': fields.boolean("Set account valuation to zero",help="If checked, the balance of the inventory account will be reseted to 0 after validating the inventory"),
    }

    def fill_inventory(self, cr, uid, ids, context=None):
        """ To Import stock inventory according to products available in the selected locations.
        @param self: The object pointer.
        @param cr: A database cursor
        @param uid: ID of the user currently logged in
        @param ids: the ID or list of IDs if we want more than one
        @param context: A standard dictionary
        @return:
        """
        if context is None:
            context = {}

        res = super(stock_fill_inventory, self).fill_inventory(
Example #48
0
class account_voucher(osv.osv):
    _inherit = 'account.voucher'

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

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

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

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

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

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

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

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

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

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

            payment_rate_currency_id = voucher.payment_rate_currency_id and voucher.payment_rate_currency_id.id

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

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

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

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

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

#    to avoid automatic Allocation

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

#automatic alocation is overide to allocate manually

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

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

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

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

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

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

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

        if not partner_id or not journal_id:
            return default

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

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


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

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

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

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

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

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

            if _remove_noise_in_o2m():
                continue

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

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

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

            if len(default['value']['line_cr_ids']) > 0:
                default['value']['pre_line'] = 1
            elif len(default['value']['line_dr_ids']) > 0:
                default['value']['pre_line'] = 1
            default['value'][
                'writeoff_amount'] = self._compute_writeoff_amount(
                    cr, uid, default['value']['line_dr_ids'],
                    default['value']['line_cr_ids'], price, ttype)
        return default
Example #49
0
    _name = "stock.fill.inventory"
    _description = "Import Inventory"

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

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

    def view_init(self, cr, uid, fields_list, context=None):
        """
         Creates view dynamically and adding fields at runtime.
         @param self: The object pointer.
         @param cr: A database cursor
         @param uid: ID of the user currently logged in
         @param context: A standard dictionary
Example #50
0
class MailMessage(osv.Model):
    _name = "sale.comment"
    _description = "Sale Comment"

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

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

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

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

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

        return comm_ids
Example #51
0
# -*- coding: utf-8 -*-
from openerp.osv import orm, fields

def selection_fn(obj, cr, uid, context=None):
    return list(enumerate(["Corge", "Grault", "Wheee", "Moog"]))

def function_fn(model, cr, uid, ids, field_name, arg, context):
    return dict((id, 3) for id in ids)

def function_fn_write(model, cr, uid, id, field_name, field_value, fnct_inv_arg, context):
    """ just so CreatorCase.export can be used
    """
    pass

models = [
    ('boolean', fields.boolean()),
    ('integer', fields.integer()),
    ('float', fields.float()),
    ('decimal', fields.float(digits=(16, 3))),
    ('string.bounded', fields.char('unknown', size=16)),
    ('string.required', fields.char('unknown', size=None, required=True)),
    ('string', fields.char('unknown', size=None)),
    ('date', fields.date()),
    ('datetime', fields.datetime()),
    ('text', fields.text()),
    ('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux"), (4, '')])),
    # here use size=-1 to store the values as integers instead of strings
    ('selection.function', fields.selection(selection_fn, size=-1)),
    # just relate to an integer
    ('many2one', fields.many2one('export.integer')),
    ('one2many', fields.one2many('export.one2many.child', 'parent_id')),
Example #52
0
class project_issue(osv.Model):
    _name = "project.issue"
    _description = "Project Issue"
    _order = "priority desc, create_date desc"
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    _mail_post_access = 'read'

    def _get_default_partner(self, cr, uid, context=None):
        if context is None:
            context = {}
        if 'default_project_id' in context:
            project = self.pool.get('project.project').browse(
                cr, uid, context['default_project_id'], context=context)
            if project and project.partner_id:
                return project.partner_id.id
        return False

    def _get_default_stage_id(self, cr, uid, context=None):
        """ Gives default stage_id """
        if context is None:
            context = {}
        return self.stage_find(cr,
                               uid, [],
                               context.get('default_project_id'),
                               [('fold', '=', False)],
                               context=context)

    def _read_group_stage_ids(self,
                              cr,
                              uid,
                              ids,
                              domain,
                              read_group_order=None,
                              access_rights_uid=None,
                              context=None):
        if context is None:
            context = {}
        access_rights_uid = access_rights_uid or uid
        stage_obj = self.pool.get('project.task.type')
        order = stage_obj._order
        # lame hack to allow reverting search, should just work in the trivial case
        if read_group_order == 'stage_id desc':
            order = "%s desc" % order
        # retrieve team_id from the context, add them to already fetched columns (ids)
        if 'default_project_id' in context:
            search_domain = [
                '|', ('project_ids', '=', context['default_project_id']),
                ('id', 'in', ids)
            ]
        else:
            search_domain = [('id', 'in', ids)]
        # perform search
        stage_ids = stage_obj._search(cr,
                                      uid,
                                      search_domain,
                                      order=order,
                                      access_rights_uid=access_rights_uid,
                                      context=context)
        result = stage_obj.name_get(cr,
                                    access_rights_uid,
                                    stage_ids,
                                    context=context)
        # restore order of the search
        result.sort(
            lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))

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

    def _compute_day(self, cr, uid, ids, fields, args, context=None):
        """
        @param cr: the current row, from the database cursor,
        @param uid: the current user’s ID for security checks,
        @param ids: List of Openday’s IDs
        @return: difference between current date and log date
        @param context: A standard dictionary for contextual values
        """
        Calendar = self.pool['resource.calendar']

        res = dict((res_id, {}) for res_id in ids)
        for issue in self.browse(cr, uid, ids, context=context):
            values = {
                'day_open': 0.0,
                'day_close': 0.0,
                'working_hours_open': 0.0,
                'working_hours_close': 0.0,
                'days_since_creation': 0.0,
                'inactivity_days': 0.0,
            }
            # if the working hours on the project are not defined, use default ones (8 -> 12 and 13 -> 17 * 5), represented by None
            calendar_id = None
            if issue.project_id and issue.project_id.resource_calendar_id:
                calendar_id = issue.project_id.resource_calendar_id.id

            dt_create_date = datetime.strptime(issue.create_date,
                                               DEFAULT_SERVER_DATETIME_FORMAT)

            if issue.date_open:
                dt_date_open = datetime.strptime(
                    issue.date_open, DEFAULT_SERVER_DATETIME_FORMAT)
                values['day_open'] = (dt_date_open - dt_create_date
                                      ).total_seconds() / (24.0 * 3600)
                values['working_hours_open'] = Calendar._interval_hours_get(
                    cr,
                    uid,
                    calendar_id,
                    dt_create_date,
                    dt_date_open,
                    timezone_from_uid=issue.user_id.id or uid,
                    exclude_leaves=False,
                    context=context)

            if issue.date_closed:
                dt_date_closed = datetime.strptime(
                    issue.date_closed, DEFAULT_SERVER_DATETIME_FORMAT)
                values['day_close'] = (dt_date_closed - dt_create_date
                                       ).total_seconds() / (24.0 * 3600)
                values['working_hours_close'] = Calendar._interval_hours_get(
                    cr,
                    uid,
                    calendar_id,
                    dt_create_date,
                    dt_date_closed,
                    timezone_from_uid=issue.user_id.id or uid,
                    exclude_leaves=False,
                    context=context)

            days_since_creation = datetime.today() - dt_create_date
            values['days_since_creation'] = days_since_creation.days
            if issue.date_action_last:
                inactive_days = datetime.today() - datetime.strptime(
                    issue.date_action_last, DEFAULT_SERVER_DATETIME_FORMAT)
            elif issue.date_last_stage_update:
                inactive_days = datetime.today() - datetime.strptime(
                    issue.date_last_stage_update,
                    DEFAULT_SERVER_DATETIME_FORMAT)
            else:
                inactive_days = datetime.today() - datetime.strptime(
                    issue.create_date, DEFAULT_SERVER_DATETIME_FORMAT)
            values['inactivity_days'] = inactive_days.days

            # filter only required values
            for field in fields:
                res[issue.id][field] = values[field]

        return res

    def on_change_project(self, cr, uid, ids, project_id, context=None):
        if project_id:
            project = self.pool.get('project.project').browse(cr,
                                                              uid,
                                                              project_id,
                                                              context=context)
            if project and project.partner_id:
                return {'value': {'partner_id': project.partner_id.id}}
        return {'value': {'partner_id': False}}

    _columns = {
        'id': fields.integer('ID', readonly=True),
        'name': fields.char('Issue', required=True),
        'active': fields.boolean('Active', required=False),
        'create_date': fields.datetime('Creation Date', readonly=True, select=True),
        'write_date': fields.datetime('Update Date', readonly=True),
        'days_since_creation': fields.function(_compute_day, string='Days since creation date', \
                                               multi='compute_day', type="integer", help="Difference in days between creation date and current date"),
        'date_deadline': fields.date('Deadline'),
        'team_id': fields.many2one('crm.team', 'Sales Team', oldname='section_id',\
                        select=True, help='Sales team to which Case belongs to.\
                             Define Responsible user and Email account for mail gateway.'                                                                                         ),
        'partner_id': fields.many2one('res.partner', 'Contact', select=1),
        'company_id': fields.many2one('res.company', 'Company'),
        'description': fields.text('Private Note'),
        'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State',
                                         track_visibility='onchange',
                                         help="A Issue's kanban state indicates special situations affecting it:\n"
                                              " * Normal is the default situation\n"
                                              " * Blocked indicates something is preventing the progress of this issue\n"
                                              " * Ready for next stage indicates the issue is ready to be pulled to the next stage",
                                         required=True),
        'email_from': fields.char('Email', size=128, help="These people will receive email.", select=1),
        'email_cc': fields.char('Watchers Emails', size=256, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
        'date_open': fields.datetime('Assigned', readonly=True, select=True),
        # Project Issue fields
        'date_closed': fields.datetime('Closed', readonly=True, select=True),
        'date': fields.datetime('Date'),
        'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
        'channel': fields.char('Channel', help="Communication channel."),
        'tag_ids': fields.many2many('project.tags', string='Tags'),
        'priority': fields.selection([('0','Low'), ('1','Normal'), ('2','High')], 'Priority', select=True),
        'stage_id': fields.many2one ('project.task.type', 'Stage',
                        track_visibility='onchange', select=True,
                        domain="[('project_ids', '=', project_id)]", copy=False),
        'project_id': fields.many2one('project.project', 'Project', track_visibility='onchange', select=True),
        'duration': fields.float('Duration'),
        'task_id': fields.many2one('project.task', 'Task', domain="[('project_id','=',project_id)]",
            help="You can link this issue to an existing task or directly create a new one from here"),
        'day_open': fields.function(_compute_day, string='Days to Assign',
                                    multi='compute_day', type="float",
                                    store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_open'], 10)}),
        'day_close': fields.function(_compute_day, string='Days to Close',
                                     multi='compute_day', type="float",
                                     store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_closed'], 10)}),
        'user_id': fields.many2one('res.users', 'Assigned to', required=False, select=1, track_visibility='onchange'),
        'working_hours_open': fields.function(_compute_day, string='Working Hours to assign the Issue',
                                              multi='compute_day', type="float",
                                              store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_open'], 10)}),
        'working_hours_close': fields.function(_compute_day, string='Working Hours to close the Issue',
                                               multi='compute_day', type="float",
                                               store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_closed'], 10)}),
        'inactivity_days': fields.function(_compute_day, string='Days since last action',
                                           multi='compute_day', type="integer", help="Difference in days between last action and current date"),
        'color': fields.integer('Color Index'),
        'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
        'date_action_last': fields.datetime('Last Action', readonly=1),
        'date_action_next': fields.datetime('Next Action', readonly=1),
        'legend_blocked': fields.related("stage_id", "legend_blocked", type="char", string='Kanban Blocked Explanation'),
        'legend_done': fields.related("stage_id", "legend_done", type="char", string='Kanban Valid Explanation'),
        'legend_normal': fields.related("stage_id", "legend_normal", type="char", string='Kanban Ongoing Explanation'),
    }

    _defaults = {
        'active':
        1,
        'team_id':
        lambda s, cr, uid, c: s.pool['crm.team']._get_default_team_id(
            cr, uid, context=c),
        'stage_id':
        lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
        'company_id':
        lambda s, cr, uid, c: s.pool['res.users']._get_company(
            cr, uid, context=c),
        'priority':
        '0',
        'kanban_state':
        'normal',
        'date_last_stage_update':
        fields.datetime.now,
        'user_id':
        lambda obj, cr, uid, context: uid,
    }

    _group_by_full = {'stage_id': _read_group_stage_ids}

    def copy(self, cr, uid, id, default=None, context=None):
        issue = self.read(cr, uid, [id], ['name'], context=context)[0]
        if not default:
            default = {}
        default = default.copy()
        default.update(name=_('%s (copy)') % (issue['name']))
        return super(project_issue, self).copy(cr,
                                               uid,
                                               id,
                                               default=default,
                                               context=context)

    def create(self, cr, uid, vals, context=None):
        context = dict(context or {})
        if vals.get('project_id') and not context.get('default_project_id'):
            context['default_project_id'] = vals.get('project_id')
        if vals.get('user_id'):
            vals['date_open'] = fields.datetime.now()
        if 'stage_id' in vals:
            vals.update(
                self.onchange_stage_id(cr,
                                       uid,
                                       None,
                                       vals.get('stage_id'),
                                       context=context)['value'])

        # context: no_log, because subtype already handle this
        create_context = dict(context, mail_create_nolog=True)
        return super(project_issue, self).create(cr,
                                                 uid,
                                                 vals,
                                                 context=create_context)

    def write(self, cr, uid, ids, vals, context=None):
        # stage change: update date_last_stage_update
        if 'stage_id' in vals:
            vals.update(
                self.onchange_stage_id(cr,
                                       uid,
                                       ids,
                                       vals.get('stage_id'),
                                       context=context)['value'])
            vals['date_last_stage_update'] = fields.datetime.now()
            if 'kanban_state' not in vals:
                vals['kanban_state'] = 'normal'
        # user_id change: update date_start
        if vals.get('user_id'):
            vals['date_open'] = fields.datetime.now()

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

    def onchange_task_id(self, cr, uid, ids, task_id, context=None):
        if not task_id:
            return {'value': {}}
        task = self.pool.get('project.task').browse(cr,
                                                    uid,
                                                    task_id,
                                                    context=context)
        return {
            'value': {
                'user_id': task.user_id.id,
            }
        }

    def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
        """ This function returns value of partner email address based on partner
            :param part: Partner's id
        """
        if partner_id:
            partner = self.pool['res.partner'].browse(cr, uid, partner_id,
                                                      context)
            return {'value': {'email_from': partner.email}}
        return {'value': {'email_from': False}}

    def get_empty_list_help(self, cr, uid, help, context=None):
        context = dict(context or {})
        context['empty_list_help_model'] = 'project.project'
        context['empty_list_help_id'] = context.get('default_project_id')
        context['empty_list_help_document_name'] = _("issues")
        return super(project_issue, self).get_empty_list_help(cr,
                                                              uid,
                                                              help,
                                                              context=context)

    # -------------------------------------------------------
    # Stage management
    # -------------------------------------------------------

    def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
        if not stage_id:
            return {'value': {}}
        stage = self.pool['project.task.type'].browse(cr,
                                                      uid,
                                                      stage_id,
                                                      context=context)
        if stage.fold:
            return {'value': {'date_closed': fields.datetime.now()}}
        return {'value': {'date_closed': False}}

    def stage_find(self,
                   cr,
                   uid,
                   cases,
                   team_id,
                   domain=[],
                   order='sequence',
                   context=None):
        """ Override of the base.stage method
            Parameter of the stage search taken from the issue:
            - type: stage type must be the same or 'both'
            - team_id: if set, stages must belong to this team or
              be a default case
        """
        if isinstance(cases, (int, long)):
            cases = self.browse(cr, uid, cases, context=context)
        # collect all team_ids
        team_ids = []
        if team_id:
            team_ids.append(team_id)
        for task in cases:
            if task.project_id:
                team_ids.append(task.project_id.id)
        # OR all team_ids and OR with case_default
        search_domain = []
        if team_ids:
            search_domain += [('|')] * (len(team_ids) - 1)
            for team_id in team_ids:
                search_domain.append(('project_ids', '=', team_id))
        search_domain += list(domain)
        # perform search, return the first found
        stage_ids = self.pool.get('project.task.type').search(cr,
                                                              uid,
                                                              search_domain,
                                                              order=order,
                                                              context=context)
        if stage_ids:
            return stage_ids[0]
        return False

    # -------------------------------------------------------
    # Mail gateway
    # -------------------------------------------------------

    def _track_subtype(self, cr, uid, ids, init_values, context=None):
        record = self.browse(cr, uid, ids[0], context=context)
        if 'kanban_state' in init_values and record.kanban_state == 'blocked':
            return 'project_issue.mt_issue_blocked'
        elif 'kanban_state' in init_values and record.kanban_state == 'done':
            return 'project_issue.mt_issue_ready'
        elif 'user_id' in init_values and record.user_id:  # assigned -> new
            return 'project_issue.mt_issue_new'
        elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence <= 1:  # start stage -> new
            return 'project_issue.mt_issue_new'
        elif 'stage_id' in init_values:
            return 'project_issue.mt_issue_stage'
        return super(project_issue, self)._track_subtype(cr,
                                                         uid,
                                                         ids,
                                                         init_values,
                                                         context=context)

    def _notification_group_recipients(self,
                                       cr,
                                       uid,
                                       ids,
                                       message,
                                       recipients,
                                       done_ids,
                                       group_data,
                                       context=None):
        """ Override the mail.thread method to handle project users and officers
        recipients. Indeed those will have specific action in their notification
        emails: creating tasks, assigning it. """
        group_project_user = self.pool['ir.model.data'].xmlid_to_res_id(
            cr, uid, 'project.group_project_user')
        for recipient in recipients:
            if recipient.id in done_ids:
                continue
            if recipient.user_ids and group_project_user in recipient.user_ids[
                    0].groups_id.ids:
                group_data['group_project_user'] |= recipient
                done_ids.add(recipient.id)
        return super(project_issue,
                     self)._notification_group_recipients(cr,
                                                          uid,
                                                          ids,
                                                          message,
                                                          recipients,
                                                          done_ids,
                                                          group_data,
                                                          context=context)

    def _notification_get_recipient_groups(self,
                                           cr,
                                           uid,
                                           ids,
                                           message,
                                           recipients,
                                           context=None):
        res = super(project_issue,
                    self)._notification_get_recipient_groups(cr,
                                                             uid,
                                                             ids,
                                                             message,
                                                             recipients,
                                                             context=context)

        new_action_id = self.pool['ir.model.data'].xmlid_to_res_id(
            cr, uid, 'project_issue.project_issue_categ_act0')
        take_action = self._notification_link_helper(cr,
                                                     uid,
                                                     ids,
                                                     'assign',
                                                     context=context)
        new_action = self._notification_link_helper(cr,
                                                    uid,
                                                    ids,
                                                    'new',
                                                    context=context,
                                                    action_id=new_action_id)

        task_record = self.browse(cr, uid, ids[0], context=context)
        actions = []
        if not task_record.user_id:
            actions.append({'url': take_action, 'title': _('I take it')})
        else:
            actions.append({'url': new_action, 'title': _('New Issue')})

        res['group_project_user'] = {'actions': actions}
        return res

    @api.cr_uid_context
    def message_get_reply_to(self, cr, uid, ids, default=None, context=None):
        """ Override to get the reply_to of the parent project. """
        issues = self.browse(cr, SUPERUSER_ID, ids, context=context)
        project_ids = set(
            [issue.project_id.id for issue in issues if issue.project_id])
        aliases = self.pool['project.project'].message_get_reply_to(
            cr, uid, list(project_ids), default=default, context=context)
        return dict(
            (issue.id,
             aliases.get(issue.project_id and issue.project_id.id or 0, False))
            for issue in issues)

    def message_get_suggested_recipients(self, cr, uid, ids, context=None):
        recipients = super(project_issue,
                           self).message_get_suggested_recipients(
                               cr, uid, ids, context=context)
        try:
            for issue in self.browse(cr, uid, ids, context=context):
                if issue.partner_id:
                    issue._message_add_suggested_recipient(
                        recipients,
                        partner=issue.partner_id,
                        reason=_('Customer'))
                elif issue.email_from:
                    issue._message_add_suggested_recipient(
                        recipients,
                        email=issue.email_from,
                        reason=_('Customer Email'))
        except AccessError:  # no read access rights -> just ignore suggested recipients because this imply modifying followers
            pass
        return recipients

    def email_split(self, cr, uid, ids, msg, context=None):
        email_list = tools.email_split((msg.get('to') or '') + ',' +
                                       (msg.get('cc') or ''))
        # check left-part is not already an alias
        issue_ids = self.browse(cr, uid, ids, context=context)
        aliases = [
            issue.project_id.alias_name for issue in issue_ids
            if issue.project_id
        ]
        return filter(lambda x: x.split('@')[0] not in aliases, email_list)

    def message_new(self, cr, uid, msg, custom_values=None, context=None):
        """ Overrides mail_thread message_new that is called by the mailgateway
            through message_process.
            This override updates the document according to the email.
        """
        if custom_values is None:
            custom_values = {}
        context = dict(context or {}, state_to='draft')
        defaults = {
            'name': msg.get('subject') or _("No Subject"),
            'email_from': msg.get('from'),
            'email_cc': msg.get('cc'),
            'partner_id': msg.get('author_id', False),
            'user_id': False,
        }
        defaults.update(custom_values)

        res_id = super(project_issue, self).message_new(cr,
                                                        uid,
                                                        msg,
                                                        custom_values=defaults,
                                                        context=context)
        email_list = self.email_split(cr, uid, [res_id], msg, context=context)
        partner_ids = self._find_partner_from_emails(cr,
                                                     uid, [res_id],
                                                     email_list,
                                                     force_create=True,
                                                     context=context)
        self.message_subscribe(cr, uid, [res_id], partner_ids, context=context)
        return res_id

    def message_update(self,
                       cr,
                       uid,
                       ids,
                       msg,
                       update_vals=None,
                       context=None):
        """ Override to update the issue according to the email. """

        email_list = self.email_split(cr, uid, ids, msg, context=context)
        partner_ids = self._find_partner_from_emails(cr,
                                                     uid,
                                                     ids,
                                                     email_list,
                                                     force_create=True,
                                                     context=context)
        self.message_subscribe(cr, uid, ids, partner_ids, context=context)
        return super(project_issue,
                     self).message_update(cr,
                                          uid,
                                          ids,
                                          msg,
                                          update_vals=update_vals,
                                          context=context)

    @api.cr_uid_ids_context
    @api.returns('mail.message', lambda value: value.id)
    def message_post(self,
                     cr,
                     uid,
                     thread_id,
                     subtype=None,
                     context=None,
                     **kwargs):
        """ Overrides mail_thread message_post so that we can set the date of last action field when
            a new message is posted on the issue.
        """
        if context is None:
            context = {}
        res = super(project_issue, self).message_post(cr,
                                                      uid,
                                                      thread_id,
                                                      subtype=subtype,
                                                      context=context,
                                                      **kwargs)
        if thread_id and subtype:
            self.write(cr,
                       SUPERUSER_ID,
                       thread_id, {'date_action_last': fields.datetime.now()},
                       context=context)
        return res
Example #53
0
            res[carrier.id] = {
                'price': price,
                'available': available
            }
        return res

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

    _defaults = {
        'active': 1,
        'free_if_more_than': False,
        'sequence': 10,
    }

    def grid_get(self, cr, uid, ids, contact_id, context=None):
        contact = self.pool.get('res.partner').browse(cr, uid, contact_id, context=context)
Example #54
0
class employee_missions(orm.Model):
    """
    To manage employee_missions """

    _inherit = "hr.employee.mission"
    _columns = {
        'fuel_requested': fields.boolean('Fuel Requested', readonly=True),
    }

    def request_fuel(self, cr, uid, ids, context=None):
        """
       Request fuel and car for mission from mission if the transport type is car.
        
       @param ids: :List of id of mission
       @return: True or False
       """
        for mission in self.browse(cr, uid, ids, context=context):
            fuel_request_obj = self.pool.get('fleet.vehicle.log.fuel')
            if mission.transport in ('1', '4') and not mission.fuel_requested:
                info = 'Mission:\t' + mission.name + '\nStart date:\t' + mission.start_date + ' - End date:\t' + mission.end_date + '\nTravel path:\t' + mission.travel_path
                request_dict = {
                    'notes': info,
                    'purpose': 'mission',
                    'payment_method': 'plan',
                    'plan_type': 'extra_fuel',
                    'state': 'draft',
                    #'date_of_travel':mission.start_date,
                    #'date_of_return':mission.end_date,
                }
                request_id = fuel_request_obj.create(cr,
                                                     uid,
                                                     request_dict,
                                                     context=context)

                #creating mission request in confirmed_d state
                #wf_service = netsvc.LocalService("workflow")
                #wf_service.trg_validate(uid, 'fuel.request', request_id, 'confirmed_s', cr)
                #wf_service.trg_validate(uid, 'fuel.request', request_id, 'confirmed_d', cr)

                #for employee in mission.mission_line:
                #cr.execute("INSERT into fuel_reuest_emp_rel values(%s,%s)",(request_id,employee.employee_id.id,))
                return self.write(cr, uid, ids, {'fuel_requested': True})

    def mission_approved(self, cr, uid, ids, context=None):
        """
        Workflow method change record state to 'approved' and 
        Transfer Mission mission_fee to move

        @return: Boolean True
        """
        voucher_obj = self.pool.get('account.voucher')
        voucher_line_obj = self.pool.get('account.voucher.line')
        account_period_obj = self.pool.get('account.period')
        for mission in self.browse(cr, uid, ids, context=context):
            mission_amount = mission.mission_fee
            if mission_amount <= 0:
                raise osv.except_osv(_('Warning!'),
                                     _('Mission fee should be more than zero'))

            if mission.mission_id.fees_account_id and mission.mission_id.journal_id and mission.mission_id.account_analytic_id:
                date = time.strftime('%Y-%m-%d')
                period = account_period_obj.find(
                    cr,
                    uid,
                    dt=date,
                    context={'company_id': mission.company_id.id})[0]
                voucher_dict = {
                    'company_id': mission.company_id.id,
                    'journal_id': mission.mission_id.journal_id.id,
                    'account_id': mission.mission_id.fees_account_id.id,
                    'period_id': period,
                    'name': mission.name + ' - ' + mission.start_date,
                    'amount': mission_amount,
                    'type': 'purchase',
                    'date': date,
                    'reference':
                    'HR/Mission/' + mission.name + ' - ' + mission.start_date,
                    'department_id': mission.department_id.id,
                    'currency': mission.mission_id.fees_currency_id.id,
                }
                voucher = voucher_obj.create(cr,
                                             uid,
                                             voucher_dict,
                                             context=context)
                voucher_line_dict = {
                    'voucher_id': voucher,
                    'account_id': mission.mission_id.fees_account_id.id,
                    'account_analytic_id':
                    mission.mission_id.account_analytic_id.id,
                    'amount': mission_amount,
                    'type': 'dr',
                }
                voucher_line_obj.create(cr,
                                        uid,
                                        voucher_line_dict,
                                        context=context)

                vouch = voucher_obj.browse(cr, uid, voucher, context=context)
                self.request_fuel(cr, uid, ids, context=context)
                self.create_grant_rights(cr, uid, ids, context=context)
                return self.write(cr, uid, ids, {
                    'state': 'approved',
                    'voucher_number': vouch.number,
                })
            else:
                raise osv.except_osv(
                    _('Error!'),
                    _("Please enter mission accounting details at the configuration of the mission destination"
                      ))
        self.create_grant_rights(cr, uid, ids, context=context)
        return self.write(cr, uid, ids, {'state': 'approved'}, context=context)
Example #55
0
        'contributors': fields.text('Contributors', readonly=True),
        'website': fields.char("Website", size=256, readonly=True),

        # attention: Incorrect field names !!
        #   installed_version refers the latest version (the one on disk)
        #   latest_version refers the installed version (the one in database)
        #   published_version refers the version available on the repository
        'installed_version': fields.function(_get_latest_version, string='Latest Version', type='char'),
        'latest_version': fields.char('Installed Version', size=64, readonly=True),
        'published_version': fields.char('Published Version', size=64, readonly=True),

        'url': fields.char('URL', size=128, readonly=True),
        'sequence': fields.integer('Sequence'),
        'dependencies_id': fields.one2many('ir.module.module.dependency', 'module_id', 'Dependencies', readonly=True),
        'auto_install': fields.boolean('Automatic Installation',
                                       help='An auto-installable module is automatically installed by the '
                                            'system when all its dependencies are satisfied. '
                                            'If the module has no dependency, it is always installed.'),
        'state': fields.selection([
            ('uninstallable', 'Not Installable'),
            ('uninstalled', 'Not Installed'),
            ('installed', 'Installed'),
            ('to upgrade', 'To be upgraded'),
            ('to remove', 'To be removed'),
            ('to install', 'To be installed')
        ], string='Status', readonly=True, select=True),
        'demo': fields.boolean('Demo Data', readonly=True),
        'license': fields.selection([
            ('GPL-2', 'GPL Version 2'),
            ('GPL-2 or any later version', 'GPL-2 or later version'),
            ('GPL-3', 'GPL Version 3'),
            ('GPL-3 or any later version', 'GPL-3 or later version'),
Example #56
0
class sio(osv.osv):
    _name = 'hr.training_sio'

    def schedule_iso(self, cr, uid, ids=None, context=None):
        if context is None:
            context = {}
        context = dict(context, mail_create_nolog=True)
        obj_warning = self.pool.get('warning.schedule')
        src_warning = obj_warning.search(cr, uid, [('name', '=', 'sio')])
        brw_warning = obj_warning.browse(cr, uid, src_warning)
        lama = brw_warning[0]
        durasi = lama.date_warning
        obj = self.pool.get('hr.training_sio')
        src = obj.search(cr, uid, [('status', '=', True),
                                   ('state', '=', 'evaluation')])
        for warning in obj.browse(cr, uid, src):
            tgl = warning.berlaku
            day_now = datetime.now()
            tgl_akhir = datetime.strptime(tgl, "%Y-%m-%d")
            nb_of_days = (tgl_akhir - day_now).days + 1
            if nb_of_days <= durasi:
                obj.write(cr, uid, [warning.id], {
                    'warning_hari': nb_of_days,
                    'link_warning': lama.id
                })
            else:
                obj.write(cr, uid, [warning.id], {
                    'warning_hari': nb_of_days,
                    'link_warning': False
                })
        return {'type': 'ir.actions.act_window_close'}

    _columns = {
        'employee_id':
        fields.many2one('hr.employee', 'Nama Peserta'),
        'nik':
        fields.related('employee_id',
                       'nik',
                       type='char',
                       relation='hr.employee',
                       string='NIK',
                       readonly=True),
        'department_id':
        fields.related('employee_id',
                       'department_id',
                       type='many2one',
                       readonly=True,
                       relation='hr.department',
                       string='Departemen',
                       store=True),
        'bukti':
        fields.binary('Bukti'),
        'berlaku':
        fields.date('Masa Berlaku', required=True),
        'nama_sertifikat':
        fields.related('analisa_id',
                       'nama_sertifikat',
                       type='many2one',
                       readonly=True,
                       relation='sertifikat',
                       string='Sertifikat'),
        'iso':
        fields.related('analisa_id',
                       'iso',
                       type='many2one',
                       readonly=True,
                       relation='iso',
                       string='Nama SIO'),
        'analisa_id':
        fields.many2one('hr_training.analisa', 'Nama Pelatihan'),
        'link_warning':
        fields.many2one('warning.schedule'),
        'warning_hari':
        fields.integer('Kadaluarsa'),
        'status':
        fields.boolean('status'),
        'state':
        fields.selection(TRAINING_STATES,
                         'Status',
                         readonly=True,
                         help="Status Training"),
        'memo':
        fields.text('catatan'),
    }
    _defaults = {
        'status': True,
        'warning_hari': 100000,
        'berlaku': fields.date.context_today,
    }
Example #57
0
        'sequence': fields.integer('Sequence'),
        'company': fields.many2one('res.company', 'Company', required=True,
            ondelete='cascade'),
        'ldap_server': fields.char('LDAP Server address', required=True),
        'ldap_server_port': fields.integer('LDAP Server port', required=True),
        'ldap_binddn': fields.char('LDAP binddn', 
            help=("The user account on the LDAP server that is used to query "
                  "the directory. Leave empty to connect anonymously.")),
        'ldap_password': fields.char('LDAP password',
            help=("The password of the user account on the LDAP server that is "
                  "used to query the directory.")),
        'ldap_filter': fields.char('LDAP filter', required=True),
        'ldap_base': fields.char('LDAP base', required=True),
        'user': fields.many2one('res.users', 'Template User',
            help="User to copy when creating new users"),
        'create_user': fields.boolean('Create user',
            help="Automatically create local user accounts for new users authenticating via LDAP"),
        'ldap_tls': fields.boolean('Use TLS',
            help="Request secure TLS/SSL encryption when connecting to the LDAP server. "
                 "This option requires a server with STARTTLS enabled, "
                 "otherwise all authentication attempts will fail."),
    }
    _defaults = {
        'ldap_server': '127.0.0.1',
        'ldap_server_port': 389,
        'sequence': 10,
        'create_user': True,
    }



class res_company(osv.osv):
class ResCompany(orm.Model):
    _inherit = 'res.company'

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

    _defaults = {
        'colipostefr_account': '',
        'colipostefr_support_city': '... PFC',
        'colipostefr_password': '',
        'colipostefr_unittest_helper': False,
        'colipostefr_webservice_message': True,
    }
Example #59
0
                    uid,
                    id,
                    {"url": url, "url_big": url_big, "url_medium": url_medium, "url_small": url_small},
                    context=context,
                )
            else:
                return False

        return self.write(cr, uid, id, {"file_db_store": value}, context=context)

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

    _defaults = {"link": True}
Example #60
0
                if not ressource_parent_type_id:
                    ressource_parent_type_id=directory.ressource_parent_type_id and directory.ressource_parent_type_id.id or False
                if not ressource_id:
                    ressource_id=directory.ressource_id and directory.ressource_id or 0
                res=self.search(cr,uid,[('id','<>',directory.id),('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id), ('revisionid', '=', revisionid)])
                if len(res):
                    return False
        if op=='create':
            res = self.search(cr, SUPERUSER_ID, [('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id), ('revisionid', '=', revisionid)])
            if len(res):
                return False
        return True
#   Overridden methods for this entity

    _columns = {
                'usedforspare': fields.boolean('Used for Spare',help="Drawings marked here will be used printing Spare Part Manual report."),
                'revisionid': fields.integer('Revision Index', required=True),
                'writable': fields.boolean('Writable'),
                'datas': fields.function(_data_get,method=True,fnct_inv=_data_set,string='File Content',type="binary"),
                'printout': fields.binary('Printout Content', help="Print PDF content."),
                'preview': fields.binary('Preview Content', help="Static preview."),
                'state':fields.selection(USED_STATES,'Status', help="The status of the product.", readonly="True", required=True),
    }    

    _defaults = {
                 'usedforspare': lambda *a: False,
                 'revisionid': lambda *a: 0,
                 'writable': lambda *a: True,
                 'state': lambda *a: 'draft',
    }