Beispiel #1
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
Beispiel #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')
            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')
Beispiel #3
0
class purchase_report(osv.osv):
    _name = "purchase.report"
    _description = "Purchases Orders"
    _auto = False
    _columns = {
        'date':
        fields.datetime('Order Date',
                        readonly=True,
                        help="Date on which this document has been created"
                        ),  # TDE FIXME master: rename into date_order
        'state':
        fields.selection([('draft', 'Request for Quotation'),
                          ('confirmed', 'Waiting Vendor Ack'),
                          ('approved', 'Approved'),
                          ('except_picking', 'Shipping Exception'),
                          ('except_invoice', 'Invoice Exception'),
                          ('done', 'Done'), ('cancel', 'Cancelled')],
                         'Order Status',
                         readonly=True),
        'product_id':
        fields.many2one('product.product', 'Product', readonly=True),
        'picking_type_id':
        fields.many2one('stock.warehouse', 'Warehouse', readonly=True),
        'location_id':
        fields.many2one('stock.location', 'Destination', readonly=True),
        'partner_id':
        fields.many2one('res.partner', 'Vendor', readonly=True),
        'pricelist_id':
        fields.many2one('product.pricelist', 'Pricelist', readonly=True),
        'date_approve':
        fields.date('Date Approved', readonly=True),
        'expected_date':
        fields.date('Expected Date', readonly=True),
        'validator':
        fields.many2one('res.users', 'Validated By', readonly=True),
        'product_uom':
        fields.many2one('product.uom',
                        'Reference Unit of Measure',
                        required=True),
        'company_id':
        fields.many2one('res.company', 'Company', readonly=True),
        'user_id':
        fields.many2one('res.users', 'Responsible', readonly=True),
        'delay':
        fields.float('Days to Validate', digits=(16, 2), readonly=True),
        'delay_pass':
        fields.float('Days to Deliver', digits=(16, 2), readonly=True),
        'quantity':
        fields.float(
            'Product Quantity',
            readonly=True),  # TDE FIXME master: rename into unit_quantity
        'price_total':
        fields.float('Total Price', readonly=True),
        'price_average':
        fields.float('Average Price', readonly=True, group_operator="avg"),
        'negociation':
        fields.float('Purchase-Standard Price',
                     readonly=True,
                     group_operator="avg"),
        'price_standard':
        fields.float('Products Value', readonly=True, group_operator="sum"),
        'nbr':
        fields.integer(
            '# of Lines',
            readonly=True),  # TDE FIXME master: rename into nbr_lines
        'category_id':
        fields.many2one('product.category', 'Product Category', readonly=True),
        'product_tmpl_id':
        fields.many2one('product.template', 'Product Template', readonly=True),
        'country_id':
        fields.many2one('res.country', 'Partner Country', readonly=True),
        'fiscal_position_id':
        fields.many2one('account.fiscal.position',
                        string='Fiscal Position',
                        oldname='fiscal_position',
                        readonly=True),
        'account_analytic_id':
        fields.many2one('account.analytic.account',
                        'Analytic Account',
                        readonly=True),
        'commercial_partner_id':
        fields.many2one('res.partner', 'Commercial Entity', readonly=True),
    }
    _order = 'date desc, price_total desc'

    def init(self, cr):
        tools.sql.drop_view_if_exists(cr, 'purchase_report')
        cr.execute("""
            create or replace view purchase_report as (
                select
                    min(l.id) as id,
                    s.date_order as date,
                    l.state,
                    s.date_approve,
                    s.minimum_planned_date as expected_date,
                    s.dest_address_id,
                    s.pricelist_id,
                    s.validator,
                    spt.warehouse_id as picking_type_id,
                    s.partner_id as partner_id,
                    s.create_uid as user_id,
                    s.company_id as company_id,
                    s.fiscal_position_id as fiscal_position_id,
                    l.product_id,
                    p.product_tmpl_id,
                    t.categ_id as category_id,
                    t.uom_id as product_uom,
                    s.location_id as location_id,
                    sum(l.product_qty/u.factor*u2.factor) as quantity,
                    extract(epoch from age(s.date_approve,s.date_order))/(24*60*60)::decimal(16,2) as delay,
                    extract(epoch from age(l.date_planned,s.date_order))/(24*60*60)::decimal(16,2) as delay_pass,
                    count(*) as nbr,
                    sum(l.price_unit*l.product_qty)::decimal(16,2) as price_total,
                    avg(100.0 * (l.price_unit*l.product_qty) / NULLIF(ip.value_float*l.product_qty/u.factor*u2.factor, 0.0))::decimal(16,2) as negociation,
                    sum(ip.value_float*l.product_qty/u.factor*u2.factor)::decimal(16,2) as price_standard,
                    (sum(l.product_qty*l.price_unit)/NULLIF(sum(l.product_qty/u.factor*u2.factor),0.0))::decimal(16,2) as price_average,
                    partner.country_id as country_id,
                    partner.commercial_partner_id as commercial_partner_id,
                    analytic_account.id as account_analytic_id
                from purchase_order_line l
                    join purchase_order s on (l.order_id=s.id)
                    join res_partner partner on s.partner_id = partner.id
                        left join product_product p on (l.product_id=p.id)
                            left join product_template t on (p.product_tmpl_id=t.id)
                            LEFT JOIN ir_property ip ON (ip.name='standard_price' AND ip.res_id=CONCAT('product.template,',t.id) AND ip.company_id=s.company_id)
                    left join product_uom u on (u.id=l.product_uom)
                    left join product_uom u2 on (u2.id=t.uom_id)
                    left join stock_picking_type spt on (spt.id=s.picking_type_id)
                    left join account_analytic_account analytic_account on (l.account_analytic_id = analytic_account.id)
                group by
                    s.company_id,
                    s.create_uid,
                    s.partner_id,
                    u.factor,
                    s.location_id,
                    l.price_unit,
                    s.date_approve,
                    l.date_planned,
                    l.product_uom,
                    s.minimum_planned_date,
                    s.pricelist_id,
                    s.validator,
                    s.dest_address_id,
                    s.fiscal_position_id,
                    l.product_id,
                    p.product_tmpl_id,
                    t.categ_id,
                    s.date_order,
                    l.state,
                    spt.warehouse_id,
                    u.uom_type,
                    u.category_id,
                    t.uom_id,
                    u.id,
                    u2.factor,
                    partner.country_id,
                    partner.commercial_partner_id,
                    analytic_account.id
            )
        """)
Beispiel #4
0
class ir_attachment(osv.osv):
    """Attachments are used to link binary files or url to any openerp document.

    External attachment storage
    ---------------------------

    The 'data' function field (_data_get,data_set) is implemented using
    _file_read, _file_write and _file_delete which can be overridden to
    implement other storage engines, shuch methods should check for other
    location pseudo uri (example: hdfs://hadoppserver)

    The default implementation is the file:dirname location that stores files
    on the local filesystem using name based on their sha1 hash
    """
    _order = 'id desc'

    def _name_get_resname(self, cr, uid, ids, object, method, context):
        data = {}
        for attachment in self.browse(cr, uid, ids, context=context):
            model_object = attachment.res_model
            res_id = attachment.res_id
            if model_object and res_id:
                model_pool = self.pool[model_object]
                res = model_pool.name_get(cr, uid, [res_id], context)
                res_name = res and res[0][1] or None
                if res_name:
                    field = self._columns.get('res_name', False)
                    if field and len(res_name) > field.size:
                        res_name = res_name[:30] + '...'
                data[attachment.id] = res_name or False
            else:
                data[attachment.id] = False
        return data

    def _storage(self, cr, uid, context=None):
        return self.pool['ir.config_parameter'].get_param(
            cr, SUPERUSER_ID, 'ir_attachment.location', 'file')

    @tools.ormcache(skiparg=3)
    def _filestore(self, cr, uid, context=None):
        return tools.config.filestore(cr.dbname)

    def force_storage(self, cr, uid, context=None):
        """Force all attachments to be stored in the currently configured storage"""
        if not self.pool['res.users'].has_group(cr, uid,
                                                'base.group_erp_manager'):
            raise AccessError(
                _('Only administrators can execute this action.'))

        location = self._storage(cr, uid, context)
        domain = {
            'db': [('store_fname', '!=', False)],
            'file': [('db_datas', '!=', False)],
        }[location]

        ids = self.search(cr, uid, domain, context=context)
        for attach in self.browse(cr, uid, ids, context=context):
            attach.write({'datas': attach.datas})
        return True

    # 'data' field implementation
    def _full_path(self, cr, uid, path):
        # sanitize ath
        path = re.sub('[.]', '', path)
        path = path.strip('/\\')
        return os.path.join(self._filestore(cr, uid), path)

    def _get_path(self, cr, uid, bin_data, sha):
        # retro compatibility
        fname = sha[:3] + '/' + sha
        full_path = self._full_path(cr, uid, fname)
        if os.path.isfile(full_path):
            return fname, full_path  # keep existing path

        # scatter files across 256 dirs
        # we use '/' in the db (even on windows)
        fname = sha[:2] + '/' + sha
        full_path = self._full_path(cr, uid, fname)
        dirname = os.path.dirname(full_path)
        if not os.path.isdir(dirname):
            os.makedirs(dirname)
        return fname, full_path

    def _file_read(self, cr, uid, fname, bin_size=False):
        full_path = self._full_path(cr, uid, fname)
        r = ''
        try:
            if bin_size:
                r = os.path.getsize(full_path)
            else:
                r = open(full_path, 'rb').read().encode('base64')
        except IOError:
            _logger.info("_read_file reading %s", full_path, exc_info=True)
        return r

    def _file_write(self, cr, uid, value, checksum):
        bin_value = value.decode('base64')
        fname, full_path = self._get_path(cr, uid, bin_value, checksum)
        if not os.path.exists(full_path):
            try:
                with open(full_path, 'wb') as fp:
                    fp.write(bin_value)
            except IOError:
                _logger.info("_file_write writing %s",
                             full_path,
                             exc_info=True)
        return fname

    def _file_delete(self, cr, uid, fname):
        count = self.search_count(cr, 1, [('store_fname', '=', fname)])
        full_path = self._full_path(cr, uid, fname)
        if not count and os.path.exists(full_path):
            try:
                os.unlink(full_path)
            except OSError:
                _logger.info("_file_delete could not unlink %s",
                             full_path,
                             exc_info=True)
            except IOError:
                # Harmless and needed for race conditions
                _logger.info("_file_delete could not unlink %s",
                             full_path,
                             exc_info=True)

    def _data_get(self, cr, uid, ids, name, arg, context=None):
        if context is None:
            context = {}
        result = {}
        bin_size = context.get('bin_size')
        for attach in self.browse(cr, uid, ids, context=context):
            if attach.store_fname:
                result[attach.id] = self._file_read(cr, uid,
                                                    attach.store_fname,
                                                    bin_size)
            else:
                result[attach.id] = attach.db_datas
        return result

    def _data_set(self, cr, uid, id, name, value, arg, context=None):
        # compute the field depending of datas, supporting the case of a empty/None datas
        bin_data = value and value.decode(
            'base64') or ''  # empty string to compute its hash
        checksum = self._compute_checksum(bin_data)
        vals = {
            'file_size': len(bin_data),
            'checksum': checksum,
        }
        # We dont handle setting data to null
        # datas is false, but file_size and checksum are not (computed as datas is an empty string)
        if not value:
            # reset computed fields
            super(ir_attachment, self).write(cr,
                                             SUPERUSER_ID, [id],
                                             vals,
                                             context=context)
            return True
        if context is None:
            context = {}
        # browse the attachment and get the file to delete
        attach = self.browse(cr, uid, id, context=context)
        fname_to_delete = attach.store_fname
        location = self._storage(cr, uid, context)
        # compute the index_content field
        vals['index_content'] = self._index(cr, SUPERUSER_ID, bin_data,
                                            attach.datas_fname,
                                            attach.mimetype),
        if location != 'db':
            # create the file
            fname = self._file_write(cr, uid, value, checksum)
            vals.update({'store_fname': fname, 'db_datas': False})
        else:
            vals.update({'store_fname': False, 'db_datas': value})
        # SUPERUSER_ID as probably don't have write access, trigger during create
        super(ir_attachment, self).write(cr,
                                         SUPERUSER_ID, [id],
                                         vals,
                                         context=context)

        # After de-referencing the file in the database, check whether we need
        # to garbage-collect it on the filesystem
        if fname_to_delete:
            self._file_delete(cr, uid, fname_to_delete)
        return True

    def _compute_checksum(self, bin_data):
        """ compute the checksum for the given datas
            :param bin_data : datas in its binary form
        """
        if bin_data:
            return hashlib.sha1(bin_data).hexdigest()
        return False

    def _compute_mimetype(self, values):
        """ compute the mimetype of the given values
            :param values : dict of values to create or write an ir_attachment
            :return mime : string indicating the mimetype, or application/octet-stream by default
        """
        mimetype = 'application/octet-stream'
        if values.get('datas_fname'):
            mimetype = mimetypes.guess_type(values['datas_fname'])[0]
        if values.get('datas'):
            mimetype = guess_mimetype(values['datas'].decode('base64'))
        return mimetype

    def _index(self, cr, uid, bin_data, datas_fname, file_type):
        """ compute the index content of the given filename, or binary data.
            This is a python implementation of the unix command 'strings'.
            :param bin_data : datas in binary form
            :return index_content : string containing all the printable character of the binary data
        """
        index_content = False
        if file_type:
            index_content = file_type.split('/')[0]
            if index_content == 'text':  # compute index_content only for text type
                words = re.findall("[^\x00-\x1F\x7F-\xFF]{4,}", bin_data)
                index_content = ustr("\n".join(words))
        return index_content

    _name = 'ir.attachment'
    _columns = {
        'name':
        fields.char('Attachment Name', required=True),
        'datas_fname':
        fields.char('File Name'),
        'description':
        fields.text('Description'),
        'res_name':
        fields.function(_name_get_resname,
                        type='char',
                        string='Resource Name',
                        store=True),
        'res_model':
        fields.char(
            'Resource Model',
            readonly=True,
            help="The database object this attachment will be attached to"),
        'res_id':
        fields.integer('Resource ID',
                       readonly=True,
                       help="The record id this is attached to"),
        'create_date':
        fields.datetime('Date Created', readonly=True),
        'create_uid':
        fields.many2one('res.users', 'Owner', readonly=True),
        'company_id':
        fields.many2one('res.company', 'Company', change_default=True),
        'type':
        fields.selection([
            ('url', 'URL'),
            ('binary', 'Binary'),
        ],
                         'Type',
                         help="Binary File or URL",
                         required=True,
                         change_default=True),
        'url':
        fields.char('Url', size=1024),
        # al: We keep shitty field names for backward compatibility with document
        'datas':
        fields.function(_data_get,
                        fnct_inv=_data_set,
                        string='File Content',
                        type="binary",
                        nodrop=True),
        'store_fname':
        fields.char('Stored Filename'),
        'db_datas':
        fields.binary('Database Data'),
        # computed fields depending on datas
        'file_size':
        fields.integer('File Size', readonly=True),
        'checksum':
        fields.char("Checksum/SHA1", size=40, select=True, readonly=True),
        'mimetype':
        fields.char('Mime Type', readonly=True),
        'index_content':
        fields.text('Indexed Content', readonly=True),
    }

    _defaults = {
        'type':
        'binary',
        'file_size':
        0,
        'mimetype':
        False,
        'company_id':
        lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(
            cr, uid, 'ir.attachment', context=c),
    }

    def _auto_init(self, cr, context=None):
        super(ir_attachment, self)._auto_init(cr, context)
        cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s',
                   ('ir_attachment_res_idx', ))
        if not cr.fetchone():
            cr.execute(
                'CREATE INDEX ir_attachment_res_idx ON ir_attachment (res_model, res_id)'
            )
            cr.commit()

    def check(self, cr, uid, ids, mode, context=None, values=None):
        """Restricts the access to an ir.attachment, according to referred model
        In the 'document' module, it is overriden to relax this hard rule, since
        more complex ones apply there.
        """
        res_ids = {}
        require_employee = False
        if ids:
            if isinstance(ids, (int, long)):
                ids = [ids]
            cr.execute(
                'SELECT DISTINCT res_model, res_id FROM ir_attachment WHERE id = ANY (%s)',
                (ids, ))
            for rmod, rid in cr.fetchall():
                if not (rmod and rid):
                    require_employee = True
                    continue
                res_ids.setdefault(rmod, set()).add(rid)
        if values:
            if values.get('res_model') and values.get('res_id'):
                res_ids.setdefault(values['res_model'],
                                   set()).add(values['res_id'])

        ima = self.pool.get('ir.model.access')
        for model, mids in res_ids.items():
            # ignore attachments that are not attached to a resource anymore when checking access rights
            # (resource was deleted but attachment was not)
            if not self.pool.get(model):
                require_employee = True
                continue
            existing_ids = self.pool[model].exists(cr, uid, mids)
            if len(existing_ids) != len(mids):
                require_employee = True
            # For related models, check if we can write to the model, as unlinking
            # and creating attachments can be seen as an update to the model
            if (mode in ['unlink', 'create']):
                ima.check(cr, uid, model, 'write')
            else:
                ima.check(cr, uid, model, mode)
            self.pool[model].check_access_rule(cr,
                                               uid,
                                               existing_ids,
                                               mode,
                                               context=context)
        if require_employee:
            if not uid == SUPERUSER_ID and not self.pool[
                    'res.users'].has_group(cr, uid, 'base.group_user'):
                raise AccessError(
                    _("Sorry, you are not allowed to access this document."))

    def _search(self,
                cr,
                uid,
                args,
                offset=0,
                limit=None,
                order=None,
                context=None,
                count=False,
                access_rights_uid=None):
        ids = super(ir_attachment,
                    self)._search(cr,
                                  uid,
                                  args,
                                  offset=offset,
                                  limit=limit,
                                  order=order,
                                  context=context,
                                  count=False,
                                  access_rights_uid=access_rights_uid)
        if not ids:
            if count:
                return 0
            return []

        # Work with a set, as list.remove() is prohibitive for large lists of documents
        # (takes 20+ seconds on a db with 100k docs during search_count()!)
        orig_ids = ids
        ids = set(ids)

        # For attachments, the permissions of the document they are attached to
        # apply, so we must remove attachments for which the user cannot access
        # the linked document.
        # Use pure SQL rather than read() as it is about 50% faster for large dbs (100k+ docs),
        # and the permissions are checked in super() and below anyway.
        cr.execute(
            """SELECT id, res_model, res_id FROM ir_attachment WHERE id = ANY(%s)""",
            (list(ids), ))
        targets = cr.dictfetchall()
        model_attachments = {}
        for target_dict in targets:
            if not target_dict['res_model']:
                continue
            # model_attachments = { 'model': { 'res_id': [id1,id2] } }
            model_attachments.setdefault(target_dict['res_model'],
                                         {}).setdefault(
                                             target_dict['res_id'] or 0,
                                             set()).add(target_dict['id'])

        # To avoid multiple queries for each attachment found, checks are
        # performed in batch as much as possible.
        ima = self.pool.get('ir.model.access')
        for model, targets in model_attachments.iteritems():
            if model not in self.pool:
                continue
            if not ima.check(cr, uid, model, 'read', False):
                # remove all corresponding attachment ids
                for attach_id in itertools.chain(*targets.values()):
                    ids.remove(attach_id)
                continue  # skip ir.rule processing, these ones are out already

            # filter ids according to what access rules permit
            target_ids = targets.keys()
            allowed_ids = [0] + self.pool[model].search(
                cr, uid, [('id', 'in', target_ids)], context=context)
            disallowed_ids = set(target_ids).difference(allowed_ids)
            for res_id in disallowed_ids:
                for attach_id in targets[res_id]:
                    ids.remove(attach_id)

        # sort result according to the original sort ordering
        result = [id for id in orig_ids if id in ids]
        return len(result) if count else list(result)

    def read(self,
             cr,
             uid,
             ids,
             fields_to_read=None,
             context=None,
             load='_classic_read'):
        if isinstance(ids, (int, long)):
            ids = [ids]
        self.check(cr, uid, ids, 'read', context=context)
        return super(ir_attachment, self).read(cr,
                                               uid,
                                               ids,
                                               fields_to_read,
                                               context=context,
                                               load=load)

    def write(self, cr, uid, ids, vals, context=None):
        if isinstance(ids, (int, long)):
            ids = [ids]
        self.check(cr, uid, ids, 'write', context=context, values=vals)
        # remove computed field depending of datas
        for field in ['file_size', 'checksum']:
            vals.pop(field, False)
        return super(ir_attachment, self).write(cr, uid, ids, vals, context)

    def copy(self, cr, uid, id, default=None, context=None):
        self.check(cr, uid, [id], 'write', context=context)
        return super(ir_attachment, self).copy(cr, uid, id, default, context)

    def unlink(self, cr, uid, ids, context=None):
        if isinstance(ids, (int, long)):
            ids = [ids]
        self.check(cr, uid, ids, 'unlink', context=context)

        # First delete in the database, *then* in the filesystem if the
        # database allowed it. Helps avoid errors when concurrent transactions
        # are deleting the same file, and some of the transactions are
        # rolled back by PostgreSQL (due to concurrent updates detection).
        to_delete = [
            a.store_fname for a in self.browse(cr, uid, ids, context=context)
            if a.store_fname
        ]
        res = super(ir_attachment, self).unlink(cr, uid, ids, context)
        for file_path in to_delete:
            self._file_delete(cr, uid, file_path)

        return res

    def create(self, cr, uid, values, context=None):
        # remove computed field depending of datas
        for field in ['file_size', 'checksum']:
            values.pop(field, False)
        # if mimetype not given, compute it !
        if 'mimetype' not in values:
            values['mimetype'] = self._compute_mimetype(values)
        self.check(cr, uid, [], mode='write', context=context, values=values)
        return super(ir_attachment, self).create(cr, uid, values, context)

    def action_get(self, cr, uid, context=None):
        return self.pool.get('ir.actions.act_window').for_xml_id(
            cr, uid, 'base', 'action_attachment', context=context)

    def invalidate_bundle(self, cr, uid, type='%', xmlid=None, context=None):
        assert type in ('%', 'css', 'js'), "Unhandled bundle type"
        xmlid = '%' if xmlid is None else xmlid + '%'
        domain = [('url', '=like', '/web/%s/%s/%%' % (type, xmlid))]
        ids = self.search(cr, uid, domain, context=context)
        if ids:
            self.unlink(cr, uid, ids, context=context)
Beispiel #5
0
class stock_production_lot(osv.osv):
    
    _inherit = 'stock.production.lot'
    _name = 'stock.production.lot'
    
    # Array que contiene los estados de los niveles de humedad
    
    _MSL_STATUS=[('ready', 'Ready'),
             ('alert', 'Alert'),
             ('donotuse','Don\'t Use')]

    #Metodo que da el nombre de los seriales
    #===========================================================================
    # def name_get(self, cr, uid, ids, context=None):
    #     result = []
    #     for record in self.browse(cr, uid, ids, context=context):
    #         name = record.name
    #         for status in self._MSL_STATUS:
    #             if status[0] == record.msl_status:
    #                 name +=  ' [' + status[1] + ']'
    #         result.append((record.id,name))
    #     return result
    #===========================================================================
    
    # Metodo que analiza el estado en que se encuentra el serial
    def _msl_calculate(self, cr, uid, ids, name, args, context=None):
        res = {}      
        for lot in self.browse(cr,uid,ids):
            res[lot.id] = {'msl_status':''} 
            control = False
            #===============================================================
            # cr.execute('select moisture_exposed_time from stock_production_lot where id=%s', (lot.id,))
            # time_read = map(lambda x: x[0], cr.fetchall())
            #===============================================================
            met, factor, open_time = 0.0, 0.0, 0.0
            # Si existe serial se busca sus variables asociadas al msl
            # las condiciones estan dadas por los porcentajes de humedad que soporte el producto
            # segun su msl 
            if lot.moisture_exposed_time:
                met = lot.moisture_exposed_time
            elif context is not None and 'moisture_exposed_time' in context:
                met = context.get('moisture_exposed_time', 0.0)
                #===========================================================
                # if met == 0.0:
                #     met = time_read[0]
                #===========================================================
            if lot.product_id.msl_id:
                factor = lot.product_id.msl_id.alarm_percentage/100
                control = lot.product_id.msl_id.control
            if lot.open_time:
                open_time = lot.open_time
            if control:
                res[lot.id] = 'ready'
            elif met == 0.0 and factor == 0.0 and open_time == 0.0:
                res[lot.id] = 'ready'
            elif met < factor * open_time:
                res[lot.id] = 'ready'
            elif met > factor * open_time and met < open_time:
                res[lot.id] = 'alert'
            elif met >= open_time:
                res[lot.id] = 'donotuse'
        return res
    
    # Se busca todos los stock.moves que tengan humedad su bodega origen ya que es el fin del movimiento
    # ademas debe ser mayor que la fecha de last baked time, y que tenga los mismos seriales el movimiento
     
    def _moisture_exposed_time_calculate(self, cr, uid, ids, name, args, context=None):           
        res = {}
        time_baked = "1900-01-01 00:00:00"
        move_pool = self.pool.get('stock.move')
        picking_pool = self.pool.get('stock.picking')
        move_ids = move_pool.search(cr, uid, [('prodlot_id', 'not in', [0.0])],context=context)
        for lot in self.browse(cr,uid,ids):
            res[lot.id] = 0.0
            if lot.product_id.msl_id:
                moisture_exposed_time = 0.0
                for move_id in move_ids:
                    move = move_pool.browse(cr,uid,move_id)
                    if lot.last_baket_time:
                        time_baked = lot.last_baket_time
                    if lot == move.prodlot_id and move.location_id.hasmoisture and datetime.strptime(move.date, "%Y-%m-%d %H:%M:%S") > datetime.strptime(time_baked, "%Y-%m-%d %H:%M:%S"):
                        moisture_exposed_time += move.duration                        
                res[lot.id] = moisture_exposed_time
                context.update({'moisture_exposed_time':moisture_exposed_time})
            if res[lot.id] == 0.0:
                picking_ids = picking_pool.search(cr, uid, [
                                ('state', '=', 'done'),
                                ('type', '=', 'internal')],context=context)
                prev_move_ids = move_pool.search(cr, uid, [
                                                      ('state', '=', 'done'),
                                                      ('location_dest_id.hasmoisture', '=', True),
                                                      ('prodlot_id', '=', lot.id),
                                                      ('picking_id','in', picking_ids), 
                                                      ('date', '>', (lot.last_baket_time if lot.last_baket_time else time_baked))],
                                            order='date desc', context=context)
                if prev_move_ids:
                    timeNow = datetime.now()
                    timeRest = (timeNow - datetime.strptime(
                        move_pool.browse(cr, uid, prev_move_ids[0]).date, '%Y-%m-%d %H:%M:%S'
                        ))
                    real_time = move_pool.total_seconds(timeRest) / 60.0 / 60.0
                    res[lot.id] = real_time 
        return res
    
    # obtiene los lotes que estan siendo modificados las variables, ver _store_rules
    def _get_lots(self, cr, uid, ids, context=None):
        lot_ids = []
        for lot in self.browse(cr, uid, ids, context=context):
                lot_ids.append(lot.id) 
        return lot_ids
    
    # obtiene los lotes que estan siendo modificados de los stock.moves, ver _store_rules
    def _get_by_moves(self, cr, uid, ids, context=None):
        lot_ids = []
        move_ids = []
        for move in self.browse(cr, uid, ids, context=context):
            if move.prodlot_id and move.prodlot_id.id not in lot_ids:               
                lot_ids.append(move.prodlot_id.id) 
        return lot_ids
    
    # obtiene los lotes que estan siendo modificados product ver _store_rules
    def _get_msl(self, cr, uid, ids, context=None):
        lot_ids = []
        lot_pool = self.pool.get('stock.production.lot')
        product_id = False
        for product in self.browse(cr, uid, ids, context=context):
            lot_ids = lot_pool.search(cr,uid,[('product_id','=',product.id)]) 
        return lot_ids
    
    # obtiene los lotes que estan siendo modificados product.msl ver _store_rules
    def _get_prod_msl(self, cr, uid, ids, context=None):
        lot_ids = []
        lot_pool = self.pool.get('stock.production.lot')
        product_pool = self.pool.get('product.product')
        product_id = False
        for product_msl in self.browse(cr, uid, ids, context=context):
            product_ids = product_pool.search(cr,uid,[('msl_id','=', product_msl.id)]) 
            lot_ids = lot_pool.search(cr,uid,[('product_id','in',product_ids)]) 
        return lot_ids
                     
    _store_rules = {
                    'product.product': (_get_msl, ['msl_id'],0),
                    'product.msl': (_get_prod_msl, ['open_time'],0),
                    'stock.production.lot': (_get_lots, ['product_id', 'moisture_exposed_time', 'last_baket_time', 'move_ids', 'msl_id','open_time'], 0),
                    'stock.move': (_get_by_moves, ['duration'], 0),
                    }

    _columns = {
                'msl_status': fields.function(_msl_calculate, 
                                              method=True, 
                                              type='selection', 
                                              selection=_MSL_STATUS, 
                                              string='MSL Status',  
                                              help="Ready, Alerted or Don't Use. If state is in alerted or don't use you should send the lot to baking"),
                'moisture_exposed_time': fields.function(_moisture_exposed_time_calculate,
                                                         method=True, type='float', 
                                                         string='Moisture exposed time', 
                                                         digits=(15,2), 
                                                         help="The time this specific lot has been exposed to moisture, is calculated according to the times in the related stock moves in locations with moisture."),                
                'msl_id': fields.related('product_id', 'msl_id', type='many2one', relation='product.msl', string="MSL", help="Moisture Sensitivity Level relates to the packaging and handling precautions for some semiconductors"),
                'open_time': fields.related('product_id', 'open_time', type='float', relation='product.product', string="Open Time in hours", help="Maximum period of time that the component can be used, after that time the component must be sent to bake."),
                'last_baket_time': fields.datetime('Last Baked Time', type='datetime',help="Last date that the component had been sent to bake."),                
                }
    
    _default = {
                'msl_status': 'ready',
                'last_baket_time': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
                }
Beispiel #6
0
class ir_property(osv.osv):
    _name = 'ir.property'

    _columns = {
        'name':
        fields.char('Name', select=1),
        'res_id':
        fields.char(
            'Resource',
            help="If not set, acts as a default value for new resources",
            select=1),
        'company_id':
        fields.many2one('res.company', 'Company', select=1),
        'fields_id':
        fields.many2one('ir.model.fields',
                        'Field',
                        ondelete='cascade',
                        required=True,
                        select=1),
        'value_float':
        fields.float('Value'),
        'value_integer':
        fields.integer('Value'),
        'value_text':
        fields.text('Value'),  # will contain (char, text)
        'value_binary':
        fields.binary('Value'),
        'value_reference':
        fields.char('Value'),
        'value_datetime':
        fields.datetime('Value'),
        'type':
        fields.selection([
            ('char', 'Char'),
            ('float', 'Float'),
            ('boolean', 'Boolean'),
            ('integer', 'Integer'),
            ('text', 'Text'),
            ('binary', 'Binary'),
            ('many2one', 'Many2One'),
            ('date', 'Date'),
            ('datetime', 'DateTime'),
            ('selection', 'Selection'),
        ],
                         'Type',
                         required=True,
                         select=1),
    }

    _defaults = {
        'type': 'many2one',
    }

    def _update_values(self, cr, uid, ids, values):
        value = values.pop('value', None)
        if not value:
            return values

        prop = None
        type_ = values.get('type')
        if not type_:
            if ids:
                prop = self.browse(cr, uid, ids[0])
                type_ = prop.type
            else:
                type_ = self._defaults['type']

        field = TYPE2FIELD.get(type_)
        if not field:
            raise osv.except_osv('Error', 'Invalid type')

        if field == 'value_reference':
            if isinstance(value, orm.BaseModel):
                value = '%s,%d' % (value._name, value.id)
            elif isinstance(value, (int, long)):
                field_id = values.get('fields_id')
                if not field_id:
                    if not prop:
                        raise ValueError()
                    field_id = prop.fields_id
                else:
                    field_id = self.pool.get('ir.model.fields').browse(
                        cr, uid, field_id)

                value = '%s,%d' % (field_id.relation, value)

        values[field] = value
        return values

    def write(self, cr, uid, ids, values, context=None):
        return super(ir_property,
                     self).write(cr,
                                 uid,
                                 ids,
                                 self._update_values(cr, uid, ids, values),
                                 context=context)

    def create(self, cr, uid, values, context=None):
        return super(ir_property,
                     self).create(cr,
                                  uid,
                                  self._update_values(cr, uid, None, values),
                                  context=context)

    def get_by_record(self, cr, uid, record, context=None):
        if record.type in ('char', 'text', 'selection'):
            return record.value_text
        elif record.type == 'float':
            return record.value_float
        elif record.type == 'boolean':
            return bool(record.value_integer)
        elif record.type == 'integer':
            return record.value_integer
        elif record.type == 'binary':
            return record.value_binary
        elif record.type == 'many2one':
            if not record.value_reference:
                return False
            model, resource_id = record.value_reference.split(',')
            value = self.pool[model].browse(cr,
                                            uid,
                                            int(resource_id),
                                            context=context)
            return value.exists()
        elif record.type == 'datetime':
            return record.value_datetime
        elif record.type == 'date':
            if not record.value_datetime:
                return False
            return time.strftime(
                '%Y-%m-%d',
                time.strptime(record.value_datetime, '%Y-%m-%d %H:%M:%S'))
        return False

    def get(self, cr, uid, name, model, res_id=False, context=None):
        domain = self._get_domain(cr, uid, name, model, context=context)
        if domain is not None:
            domain = [('res_id', '=', res_id)] + domain
            #make the search with company_id asc to make sure that properties specific to a company are given first
            nid = self.search(cr,
                              uid,
                              domain,
                              limit=1,
                              order='company_id asc',
                              context=context)
            if not nid: return False
            record = self.browse(cr, uid, nid[0], context=context)
            return self.get_by_record(cr, uid, record, context=context)
        return False

    def _get_domain(self, cr, uid, prop_name, model, context=None):
        context = context or {}
        cr.execute('select id from ir_model_fields where name=%s and model=%s',
                   (prop_name, model))
        res = cr.fetchone()
        if not res:
            return None

        cid = context.get('force_company')
        if not cid:
            company = self.pool.get('res.company')
            cid = company._company_default_get(cr,
                                               uid,
                                               model,
                                               res[0],
                                               context=context)

        return [('fields_id', '=', res[0]), ('company_id', 'in', [cid, False])]

    @api.model
    def get_multi(self, name, model, ids):
        """ Read the property field `name` for the records of model `model` with
            the given `ids`, and return a dictionary mapping `ids` to their
            corresponding value.
        """
        if not ids:
            return {}

        domain = self._get_domain(name, model)
        if domain is None:
            return dict.fromkeys(ids, False)

        # retrieve the values for the given ids and the default value, too
        refs = {('%s,%s' % (model, id)): id for id in ids}
        refs[False] = False
        domain += [('res_id', 'in', list(refs))]

        # note: order by 'company_id asc' will return non-null values first
        props = self.search(domain, order='company_id asc')
        result = {}
        for prop in props:
            # for a given res_id, take the first property only
            id = refs.pop(prop.res_id, None)
            if id is not None:
                result[id] = self.get_by_record(prop)

        # set the default value to the ids that are not in result
        default_value = result.pop(False, False)
        for id in ids:
            result.setdefault(id, default_value)

        return result

    @api.model
    def set_multi(self, name, model, values):
        """ Assign the property field `name` for the records of model `model`
            with `values` (dictionary mapping record ids to their value).
        """
        def clean(value):
            return value.id if isinstance(value, models.BaseModel) else value

        if not values:
            return

        domain = self._get_domain(name, model)
        if domain is None:
            raise Exception()

        # retrieve the default value for the field
        default_value = clean(self.get(name, model))

        # retrieve the properties corresponding to the given record ids
        self._cr.execute(
            "SELECT id FROM ir_model_fields WHERE name=%s AND model=%s",
            (name, model))
        field_id = self._cr.fetchone()[0]
        company_id = self.env.context.get(
            'force_company') or self.env['res.company']._company_default_get(
                model, field_id)
        refs = {('%s,%s' % (model, id)): id for id in values}
        props = self.search([
            ('fields_id', '=', field_id),
            ('company_id', '=', company_id),
            ('res_id', 'in', list(refs)),
        ])

        # modify existing properties
        for prop in props:
            id = refs.pop(prop.res_id)
            value = clean(values[id])
            if value == default_value:
                prop.unlink()
            elif value != clean(prop.get_by_record(prop)):
                prop.write({'value': value})

        # create new properties for records that do not have one yet
        for ref, id in refs.iteritems():
            value = clean(values[id])
            if value != default_value:
                self.create({
                    'fields_id': field_id,
                    'company_id': company_id,
                    'res_id': ref,
                    'name': name,
                    'value': value,
                    'type': self.env[model]._fields[name].type,
                })

    @api.model
    def search_multi(self, name, model, operator, value):
        """ Return a domain for the records that match the given condition. """
        default_matches = False
        include_zero = False

        field = self.env[model]._fields[name]
        if field.type == 'many2one':
            comodel = field.comodel_name

            def makeref(value):
                return value and '%s,%s' % (comodel, value)

            if operator == "=":
                value = makeref(value)
                # if searching properties not set, search those not in those set
                if value is False:
                    default_matches = True
            elif operator in ('!=', '<=', '<', '>', '>='):
                value = makeref(value)
            elif operator in ('in', 'not in'):
                value = map(makeref, value)
            elif operator in ('=like', '=ilike', 'like', 'not like', 'ilike',
                              'not ilike'):
                # most probably inefficient... but correct
                target = self.env[comodel]
                target_names = target.name_search(value,
                                                  operator=operator,
                                                  limit=None)
                target_ids = map(itemgetter(0), target_names)
                operator, value = 'in', map(makeref, target_ids)
        elif field.type in ('integer', 'float'):
            # No record is created in ir.property if the field's type is float or integer with a value
            # equal to 0. Then to match with the records that are linked to a property field equal to 0,
            # the negation of the operator must be taken  to compute the goods and the domain returned
            # to match the searched records is just the opposite.
            if value == 0 and operator == '=':
                operator = '!='
                include_zero = True
            elif value <= 0 and operator == '>=':
                operator = '<'
                include_zero = True
            elif value <= 0 and operator == '>':
                operator = '<='
                include_zero = True
            elif value >= 0 and operator == '<=':
                operator = '>'
                include_zero = True
            elif value >= 0 and operator == '<':
                operator = '>='
                include_zero = True

        # retrieve the properties that match the condition
        domain = self._get_domain(name, model)
        if domain is None:
            raise Exception()
        props = self.search(domain +
                            [(TYPE2FIELD[field.type], operator, value)])

        # retrieve the records corresponding to the properties that match
        good_ids = []
        for prop in props:
            if prop.res_id:
                res_model, res_id = prop.res_id.split(',')
                good_ids.append(int(res_id))
            else:
                default_matches = True

        if include_zero:
            return [('id', 'not in', good_ids)]
        elif default_matches:
            # exclude all records with a property that does not match
            all_ids = []
            props = self.search(domain + [('res_id', '!=', False)])
            for prop in props:
                res_model, res_id = prop.res_id.split(',')
                all_ids.append(int(res_id))
            bad_ids = list(set(all_ids) - set(good_ids))
            return [('id', 'not in', bad_ids)]
        else:
            return [('id', 'in', good_ids)]
Beispiel #7
0
class banking_export_sdd(orm.Model):
    '''SEPA Direct Debit export'''
    _name = 'banking.export.sdd'
    _description = __doc__
    _rec_name = 'filename'

    def _generate_filename(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for sepa_file in self.browse(cr, uid, ids, context=context):
            ref = sepa_file.payment_order_ids[0].reference
            if ref:
                label = unidecode(ref.replace('/', '-'))
            else:
                label = 'error'
            res[sepa_file.id] = 'sdd_%s.xml' % label
        return res

    _columns = {
        'payment_order_ids': fields.many2many(
            'payment.order',
            'account_payment_order_sdd_rel',
            'banking_export_sepa_id', 'account_order_id',
            'Payment Orders',
            readonly=True),
        'nb_transactions': fields.integer(
            'Number of Transactions', readonly=True),
        'total_amount': fields.float(
            'Total Amount', digits_compute=dp.get_precision('Account'),
            readonly=True),
        'batch_booking': fields.boolean(
            'Batch Booking', readonly=True,
            help="If true, the bank statement will display only one credit "
                 "line for all the direct debits of the SEPA file ; if false, "
                 "the bank statement will display one credit line per direct "
                 "debit of the SEPA file."),
        'charge_bearer': fields.selection([
            ('SLEV', 'Following Service Level'),
            ('SHAR', 'Shared'),
            ('CRED', 'Borne by Creditor'),
            ('DEBT', 'Borne by Debtor'),
        ], 'Charge Bearer', readonly=True,
            help="Following service level : transaction charges are to be "
                 "applied following the rules agreed in the service level and/or "
                 "scheme (SEPA Core messages must use this). Shared : "
                 "transaction charges on the creditor side are to be borne by "
                 "the creditor, transaction charges on the debtor side are to be "
                 "borne by the debtor. Borne by creditor : all transaction "
                 "charges are to be borne by the creditor. Borne by debtor : "
                 "all transaction charges are to be borne by the debtor."),
        'create_date': fields.datetime('Generation Date', readonly=True),
        'file': fields.binary('SEPA File', readonly=True),
        'filename': fields.function(
            _generate_filename, type='char', size=256,
            string='Filename', readonly=True, store=True),
        'state': fields.selection([
            ('draft', 'Draft'),
            ('sent', 'Sent'),
            ('done', 'Reconciled'),
        ], 'State', readonly=True),
    }

    _defaults = {
        'state': 'draft',
    }
Beispiel #8
0
class laboratory_ihce(osv.Model):
    _name = 'laboratory.ihce'

    def _get_percent(self, cr, uid, ids, field, arg, context=None):
        res = {}
        for rows in self.browse(cr, uid, ids, context=context):
            percent = 0
            suma = 0
            con = 0
            for row in rows:
                for line in row.lines_services:
                    if line.state != 'detained':
                        suma += line.percent
                        con = con + 1

                if suma > 0:
                    percent = suma / con
                res[row.id] = percent

        return res

    def _get_services(self, cr, uid, ids, field, arg, context=None):
        res = {}
        for rows in self.browse(cr, uid, ids, context=context):
            suma = 0
            for row in rows:
                for line in row.lines_services:
                    if line.state == 'pre_done' or line.state == 'done':
                        suma = suma + 1
                res[row.id] = suma

        return res

    def _get_advices(self, cr, uid, ids, field, arg, context=None):
        res = {}
        for rows in self.browse(cr, uid, ids, context=context):
            suma = 0
            for row in rows:
                res[row.id] = len(row.lines_advices)

        return res

    def _get_state(self, cr, uid, ids, field, arg, context=None):
        res = {}

        for rows in self.browse(cr, uid, ids, context=context):
            done = False
            detained = False
            pro = False
            for row in rows:
                if row.state == 'process':
                    for line in row.lines_services:
                        if line.state == 'pre_done' or line.state == 'done':
                            done = True
                        elif line.state == 'detained':
                            detained = True
                        else:
                            pro = True

                    if done and not detained and not pro:
                        #~ Si todos los servicios estan terminados cambiamos el estado y enviamos la encuesta
                        self.send_test(cr, uid, ids, context=context)
                        res[row.id] = True
                    else:
                        if done and detained and not pro:
                            #~ Si todos los servicios estan terminados cambiamos el estado y enviamos la encuesta
                            self.send_test(cr, uid, ids, context=context)
                            res[row.id] = True
                        else:
                            if (done and detained and pro) or (
                                    pro and done) or (detained and pro) or pro:
                                self.write(cr, uid, row.id,
                                           {'state': 'process'})
                                res[row.id] = False
                            else:
                                if not done and not pro and detained:
                                    self.write(cr, uid, row.id,
                                               {'state': 'detained'})

        return res

    _columns = {
        'name':
        fields.char("ID de Proyecto", size=200),
        'company_id':
        fields.many2one('companies.ihce', 'Beneficiario'),
        'date':
        fields.datetime("Fecha de inicio"),
        'percent':
        fields.function(_get_percent,
                        type='integer',
                        string="Porcentaje de avance"),
        'notes':
        fields.text("Observación General"),
        'state':
        fields.selection([('process', 'Proceso'),
                          ('stand', 'Encuesta Enviada'), ('done', 'Terminado'),
                          ('detained', 'Abandonado')],
                         'Estado',
                         select=True),
        'servicio':
        fields.function(_get_services, type='integer', string="No. Servicios"),
        'advices':
        fields.function(_get_advices, type='integer', string="No. Asesorías"),
        'user_id':
        fields.many2one(
            'res.users',
            "Responsable",
            help="Es el usuario al que se le contarán los indicadores."),
        'lines_services':
        fields.one2many('desing.laboratory', 'id_project', 'Servicios'),
        'lines_advices':
        fields.one2many('advices.laboratory', 'laboratory', 'Asesorías'),
        'url_test':
        fields.char("Url de Encuesta", size=200),
        'test':
        fields.one2many('test.laboratory', 'laboratory',
                        "Encuesta de Satisfacción"),
        'state_done':
        fields.function(_get_state,
                        type='boolean',
                        string="Estado del proyecto"),
        'tests_bol':
        fields.boolean("Encuestas"),
        'sector':
        fields.many2one('sector.actividad.economica',
                        "Sector",
                        help="Sector económico"),
    }

    _defaults = {
        'state': 'process',
        'percent': 0,
        'user_id': lambda obj, cr, uid, context: uid,
        'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
        'tests_bol': False,
    }

    _order = "name desc"

    def create(self, cr, uid, vals, context=None):
        return super(laboratory_ihce, self).create(cr, uid, vals, context)

    def write(self, cr, uid, ids, vals, context=None):
        return super(laboratory_ihce, self).write(cr,
                                                  uid,
                                                  ids,
                                                  vals,
                                                  context=context)

    #~ Función para enviar correo con la liga de encuesta de satisfacción
    def send_test(self, cr, uid, ids, context=None):
        fecha_actual = datetime.now()
        email_vals = {}
        row = self.browse(cr, uid, ids[0], context=context)

        mail_message_obj = self.pool.get('mail.mail')
        user_row = self.pool.get('res.users').browse(cr, uid, row.user_id.id)
        companies = self.pool.get('companies.ihce').browse(cr,
                                                           uid,
                                                           row.company_id.id,
                                                           context=context)

        url = "http://192.241.169.197/encuesta/index.php?&token=" + str(row.id)
        self.write(cr,
                   uid,
                   row.id, {
                       'url_test': url,
                       'state': 'done'
                   },
                   context=context)

        if user_row.email:
            subject = "ENCUESTA DE SATISFACCIÓN LABORATORIO DE DISEÑO"

            body_text = "Estimado " + str(
                companies.name.encode('utf-8')
            ) + "</br></br><p>Para brindarte un mejor servicio el Laboratorio de Diseño te envita a contestar la siguiente encuesta de satisfacción.</p> <p></br></br>" + str(
                url) + "</p> </br></br> <p>Gracias.</p>"

            email_vals.update({
                'subject': subject,
                'body_html': body_text,
                'body': body_text,
                'email_to': companies.email,
                'email_from': user_row.email
            })
            mail_id = mail_message_obj.create(cr, uid, email_vals)
            mail_message_obj.send(cr,
                                  uid, [mail_id],
                                  False,
                                  None,
                                  context=context)

            #~ Linea de historial del beneficiario
            self.pool.get('crm.ihce').create(
                cr,
                uid, {
                    'company_id':
                    row.company_id.id,
                    'date':
                    fecha_actual,
                    'name':
                    'Se ha enviado encuesta de satisfacción al beneficiario del proyecto '
                    + str(row.name.encode('utf-8')) +
                    " del laboratorio de diseño.",
                    'user':
                    uid,
                    'date_compromise':
                    fecha_actual,
                    'state':
                    'done'
                },
                context=context)

            #~ self.message_post(cr, uid, [row.id], body=_("Encuesta Enviada"), context=context)

        else:
            raise osv.except_osv(_('Advertencia!'),
                                 _('El usuario no tiene correo electrónico!'))

        return True
Beispiel #9
0
class PaymentTransaction(osv.Model):
    """ Transaction Model. Each specific acquirer can extend the model by adding
    its own fields.

    Methods that can be added in an acquirer-specific implementation:

     - ``<name>_create``: method receiving values used when creating a new
       transaction and that returns a dictionary that will update those values.
       This method can be used to tweak some transaction values.

    Methods defined for convention, depending on your controllers:

     - ``<name>_form_feedback(self, cr, uid, data, context=None)``: method that
       handles the data coming from the acquirer after the transaction. It will
       generally receives data posted by the acquirer after the transaction.
    """
    _name = 'payment.transaction'
    _description = 'Payment Transaction'
    _inherit = ['mail.thread']
    _order = 'id desc'
    _rec_name = 'reference'

    _columns = {
        'date_create':
        fields.datetime('Creation Date', readonly=True, required=True),
        'date_validate':
        fields.datetime('Validation Date'),
        'acquirer_id':
        fields.many2one(
            'payment.acquirer',
            'Acquirer',
            required=True,
        ),
        'type':
        fields.selection([('server2server', 'Server To Server'),
                          ('form', 'Form')],
                         string='Type',
                         required=True),
        'state':
        fields.selection([('draft', 'Draft'), ('pending', 'Pending'),
                          ('done', 'Done'), ('error', 'Error'),
                          ('cancel', 'Canceled')],
                         'Status',
                         required=True,
                         track_visibility='onchange',
                         copy=False),
        'state_message':
        fields.text(
            'Message',
            help=
            'Field used to store error and/or validation messages for information'
        ),
        # payment
        'amount':
        fields.float('Amount',
                     required=True,
                     digits=(16, 2),
                     track_visibility='always',
                     help='Amount in cents'),
        'fees':
        fields.float(
            'Fees',
            digits=(16, 2),
            track_visibility='always',
            help=
            'Fees amount; set by the system because depends on the acquirer'),
        'currency_id':
        fields.many2one('res.currency', 'Currency', required=True),
        'reference':
        fields.char('Order Reference', required=True),
        'acquirer_reference':
        fields.char(
            'Acquirer Order Reference',
            help='Reference of the TX as stored in the acquirer database'),
        # duplicate partner / transaction data to store the values at transaction time
        'partner_id':
        fields.many2one(
            'res.partner',
            'Partner',
            track_visibility='onchange',
        ),
        'partner_name':
        fields.char('Partner Name'),
        'partner_lang':
        fields.char('Lang'),
        'partner_email':
        fields.char('Email'),
        'partner_zip':
        fields.char('Zip'),
        'partner_address':
        fields.char('Address'),
        'partner_city':
        fields.char('City'),
        'partner_country_id':
        fields.many2one('res.country', 'Country', required=True),
        'partner_phone':
        fields.char('Phone'),
        'partner_reference':
        fields.char('Partner Reference',
                    help='Reference of the customer in the acquirer database'),
    }

    def _check_reference(self, cr, uid, ids, context=None):
        transaction = self.browse(cr, uid, ids[0], context=context)
        if transaction.state not in ['cancel', 'error']:
            if self.search(cr,
                           uid, [('reference', '=', transaction.reference),
                                 ('id', '!=', transaction.id)],
                           context=context,
                           count=True):
                return False
        return True

    _constraints = [
        (_check_reference, 'The payment transaction reference must be unique!',
         ['reference', 'state']),
    ]

    _defaults = {
        'date_create': fields.datetime.now,
        'type': 'form',
        'state': 'draft',
        'partner_lang': 'en_US',
    }

    def create(self, cr, uid, values, context=None):
        Acquirer = self.pool['payment.acquirer']

        if values.get('partner_id'):  # @TDENOTE: not sure
            values.update(
                self.on_change_partner_id(cr,
                                          uid,
                                          None,
                                          values.get('partner_id'),
                                          context=context)['values'])

        # call custom create method if defined (i.e. ogone_create for ogone)
        if values.get('acquirer_id'):
            acquirer = self.pool['payment.acquirer'].browse(
                cr, uid, values.get('acquirer_id'), context=context)

            # compute fees
            custom_method_name = '%s_compute_fees' % acquirer.provider
            if hasattr(Acquirer, custom_method_name):
                fees = getattr(Acquirer,
                               custom_method_name)(cr,
                                                   uid,
                                                   acquirer.id,
                                                   values.get('amount', 0.0),
                                                   values.get('currency_id'),
                                                   values.get('country_id'),
                                                   context=None)
                values['fees'] = float_round(fees, 2)

            # custom create
            custom_method_name = '%s_create' % acquirer.provider
            if hasattr(self, custom_method_name):
                values.update(
                    getattr(self, custom_method_name)(cr,
                                                      uid,
                                                      values,
                                                      context=context))

        return super(PaymentTransaction, self).create(cr,
                                                      uid,
                                                      values,
                                                      context=context)

    def write(self, cr, uid, ids, values, context=None):
        Acquirer = self.pool['payment.acquirer']
        if ('acquirer_id' in values
                or 'amount' in values) and 'fees' not in values:
            # The acquirer or the amount has changed, and the fees are not explicitely forced. Fees must be recomputed.
            if isinstance(ids, (int, long)):
                ids = [ids]
            for txn_id in ids:
                vals = dict(values)
                vals['fees'] = 0.0
                transaction = self.browse(cr, uid, txn_id, context=context)
                if 'acquirer_id' in values:
                    acquirer = Acquirer.browse(
                        cr, uid, values['acquirer_id'],
                        context=context) if values['acquirer_id'] else None
                else:
                    acquirer = transaction.acquirer_id
                if acquirer:
                    custom_method_name = '%s_compute_fees' % acquirer.provider
                    if hasattr(Acquirer, custom_method_name):
                        amount = (values['amount'] if 'amount' in values else
                                  transaction.amount) or 0.0
                        currency_id = values.get(
                            'currency_id') or transaction.currency_id.id
                        country_id = values.get(
                            'partner_country_id'
                        ) or transaction.partner_country_id.id
                        fees = getattr(Acquirer,
                                       custom_method_name)(cr,
                                                           uid,
                                                           acquirer.id,
                                                           amount,
                                                           currency_id,
                                                           country_id,
                                                           context=None)
                        vals['fees'] = float_round(fees, 2)
                res = super(PaymentTransaction, self).write(cr,
                                                            uid,
                                                            txn_id,
                                                            vals,
                                                            context=context)
            return res
        return super(PaymentTransaction, self).write(cr,
                                                     uid,
                                                     ids,
                                                     values,
                                                     context=context)

    def on_change_partner_id(self, cr, uid, ids, partner_id, context=None):
        partner = None
        if partner_id:
            partner = self.pool['res.partner'].browse(cr,
                                                      uid,
                                                      partner_id,
                                                      context=context)
        return {
            'values': {
                'partner_name':
                partner and partner.name or False,
                'partner_lang':
                partner and partner.lang or 'en_US',
                'partner_email':
                partner and partner.email or False,
                'partner_zip':
                partner and partner.zip or False,
                'partner_address':
                _partner_format_address(partner and partner.street or '',
                                        partner and partner.street2 or ''),
                'partner_city':
                partner and partner.city or False,
                'partner_country_id':
                partner and partner.country_id.id or False,
                'partner_phone':
                partner and partner.phone or False,
            }
        }

    # --------------------------------------------------
    # FORM RELATED METHODS
    # --------------------------------------------------

    def form_feedback(self, cr, uid, data, acquirer_name, context=None):
        invalid_parameters, tx = None, None

        tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name
        if hasattr(self, tx_find_method_name):
            tx = getattr(self, tx_find_method_name)(cr,
                                                    uid,
                                                    data,
                                                    context=context)

        invalid_param_method_name = '_%s_form_get_invalid_parameters' % acquirer_name
        if hasattr(self, invalid_param_method_name):
            invalid_parameters = getattr(self, invalid_param_method_name)(
                cr, uid, tx, data, context=context)

        if invalid_parameters:
            _error_message = '%s: incorrect tx data:\n' % (acquirer_name)
            for item in invalid_parameters:
                _error_message += '\t%s: received %s instead of %s\n' % (
                    item[0], item[1], item[2])
            _logger.error(_error_message)
            return False

        feedback_method_name = '_%s_form_validate' % acquirer_name
        if hasattr(self, feedback_method_name):
            return getattr(self, feedback_method_name)(cr,
                                                       uid,
                                                       tx,
                                                       data,
                                                       context=context)

        return True

    # --------------------------------------------------
    # SERVER2SERVER RELATED METHODS
    # --------------------------------------------------

    def s2s_create(self, cr, uid, values, cc_values, context=None):
        tx_id, tx_result = self.s2s_send(cr,
                                         uid,
                                         values,
                                         cc_values,
                                         context=context)
        self.s2s_feedback(cr, uid, tx_id, tx_result, context=context)
        return tx_id

    def s2s_send(self, cr, uid, values, cc_values, context=None):
        """ Create and send server-to-server transaction.

        :param dict values: transaction values
        :param dict cc_values: credit card values that are not stored into the
                               payment.transaction object. Acquirers should
                               handle receiving void or incorrect cc values.
                               Should contain :

                                - holder_name
                                - number
                                - cvc
                                - expiry_date
                                - brand
                                - expiry_date_yy
                                - expiry_date_mm
        """
        tx_id, result = None, None

        if values.get('acquirer_id'):
            acquirer = self.pool['payment.acquirer'].browse(
                cr, uid, values.get('acquirer_id'), context=context)
            custom_method_name = '_%s_s2s_send' % acquirer.provider
            if hasattr(self, custom_method_name):
                tx_id, result = getattr(self,
                                        custom_method_name)(cr,
                                                            uid,
                                                            values,
                                                            cc_values,
                                                            context=context)

        if tx_id is None and result is None:
            tx_id = super(PaymentTransaction, self).create(cr,
                                                           uid,
                                                           values,
                                                           context=context)
        return (tx_id, result)

    def s2s_feedback(self, cr, uid, tx_id, data, context=None):
        """ Handle the feedback of a server-to-server transaction. """
        tx = self.browse(cr, uid, tx_id, context=context)
        invalid_parameters = None

        invalid_param_method_name = '_%s_s2s_get_invalid_parameters' % tx.acquirer_id.provider
        if hasattr(self, invalid_param_method_name):
            invalid_parameters = getattr(self, invalid_param_method_name)(
                cr, uid, tx, data, context=context)

        if invalid_parameters:
            _error_message = '%s: incorrect tx data:\n' % (tx.acquirer_id.name)
            for item in invalid_parameters:
                _error_message += '\t%s: received %s instead of %s\n' % (
                    item[0], item[1], item[2])
            _logger.error(_error_message)
            return False

        feedback_method_name = '_%s_s2s_validate' % tx.acquirer_id.provider
        if hasattr(self, feedback_method_name):
            return getattr(self, feedback_method_name)(cr,
                                                       uid,
                                                       tx,
                                                       data,
                                                       context=context)

        return True

    def s2s_get_tx_status(self, cr, uid, tx_id, context=None):
        """ Get the tx status. """
        tx = self.browse(cr, uid, tx_id, context=context)

        invalid_param_method_name = '_%s_s2s_get_tx_status' % tx.acquirer_id.provider
        if hasattr(self, invalid_param_method_name):
            return getattr(self, invalid_param_method_name)(cr,
                                                            uid,
                                                            tx,
                                                            context=context)

        return True
Beispiel #10
0
class vit_rework_wizard(osv.osv_memory):
    _name = 'vit.rework.wizard'

    def default_get(self, cr, uid, fields, context=None):
        if context is None:
            context = {}
        res = super(vit_rework_wizard, self).default_get(cr,
                                                         uid,
                                                         fields,
                                                         context=context)
        if context.get('active_id'):
            move = self.pool.get('stock.move').browse(cr,
                                                      uid,
                                                      context['active_id'],
                                                      context=context)
            if 'workorder_id' in fields:
                res.update({'workorder_id': context['active_id']})
        return res

    _columns = {
        'workorder_id':
        fields.many2one(
            'mrp.production.workcenter.line',
            'Work Order',
        ),
        'partner_id':
        fields.many2one('res.partner', 'Partner'),
        'date':
        fields.datetime('Schedule Date',
                        required=True,
                        help='waktu yang diminta untuk barang-barang ini'),
        'rework_detail_ids':
        fields.one2many('vit.rework.detail.wizard',
                        'wizard_id',
                        string='Details Product'),
    }

    _defaults = {
        'date': fields.datetime.now,
    }

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

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

        partner_id = False
        #import pdb;pdb.set_trace()
        for data in self.browse(cr, uid, ids, context=context):
            if not data.rework_detail_ids:
                raise osv.except_osv(_('Error'),
                                     _('Data Product tidak boleh kosong !.'))
            if data.partner_id:
                partner_id = data.partner_id.id
            # create picking
            # picking_id = picking_obj.create(cr,uid,{'partner_id': partner_id,
            #                                         'origin': data.workorder_id.production_id.name+' ['+data.workorder_id.name+']',
            #                                         'workorder_id':context['active_id'],
            #                                         'picking_type_id':3,#internal transfer
            #                                         'min_date': data.date,
            #                                         'invoice_state':'none',
            #                                         'move_type':'direct'},context=context)

            # diganti langsung ke stock.move karena jadi ada error:
            # MissingError: ('MissingError', u'One of the documents you are trying to access has been deleted, please try again after refreshing.')

            moves = []
            for move in data.rework_detail_ids:
                product_id = move.product_id.id
                product_name = move.product_id.name
                move_qty = move.qty
                move_uom = move.uom_id.id

                # Create stock.move
                move_id = move_obj.create(
                    cr,
                    uid,
                    {
                        'product_id':
                        product_id,
                        #'picking_id':picking_id,
                        'workorder_id':
                        context['active_id'],
                        'origin':
                        data.workorder_id.production_id.name + ' [' +
                        data.workorder_id.name + ']',
                        'name':
                        product_name,
                        'product_uom_qty':
                        move_qty,
                        'product_uom':
                        move_uom,
                        'location_id':
                        12,  # WH/stock
                        'location_dest_id':
                        5,  #virtual loss
                    },
                    context=context)

                moves.append(move_id)

        return moves
Beispiel #11
0
class hr_so_project(osv.osv_memory):
    _name = 'hr.sign.out.project'
    _description = 'Sign Out By Project'
    _columns = {
        'account_id':
        fields.many2one('account.analytic.account',
                        'Project / Analytic Account',
                        domain=[('type', '=', 'normal')]),
        'info':
        fields.char('Work Description', size=256, required=True),
        'date_start':
        fields.datetime('Starting Date', readonly=True),
        'date':
        fields.datetime('Closing Date'),
        'analytic_amount':
        fields.float('Minimum Analytic Amount'),
        'name':
        fields.char('Employee\'s Name', size=32, required=True, readonly=True),
        'state':
        fields.related('emp_id',
                       'state',
                       string='Current Status',
                       type='selection',
                       selection=[('present', 'Present'),
                                  ('absent', 'Absent')],
                       required=True,
                       readonly=True),
        'server_date':
        fields.datetime('Current Date', required=True, readonly=True),
        'emp_id':
        fields.many2one('hr.employee', 'Employee ID')
    }

    def _get_empid(self, cr, uid, context=None):
        emp_obj = self.pool.get('hr.employee')
        emp_ids = emp_obj.search(cr,
                                 uid, [('user_id', '=', uid)],
                                 context=context)
        if emp_ids:
            for employee in emp_obj.browse(cr, uid, emp_ids, context=context):
                return {
                    'name': employee.name,
                    'state': employee.state,
                    'emp_id': emp_ids[0],
                    'server_date': time.strftime('%Y-%m-%d %H:%M:%S')
                }

    def _get_empid2(self, cr, uid, context=None):
        res = self._get_empid(cr, uid, context=context)
        cr.execute(
            'select name,action from hr_attendance where employee_id=%s order by name desc limit 1',
            (res['emp_id'], ))

        res['server_date'] = time.strftime('%Y-%m-%d %H:%M:%S')
        date_start = cr.fetchone()

        if date_start:
            res['date_start'] = date_start[0]
        return res

    def default_get(self, cr, uid, fields_list, context=None):
        res = super(hr_so_project, self).default_get(cr,
                                                     uid,
                                                     fields_list,
                                                     context=context)
        res.update(self._get_empid2(cr, uid, context=context))
        return res

    def _write(self, cr, uid, data, emp_id, context=None):
        timesheet_obj = self.pool.get('hr.analytic.timesheet')
        emp_obj = self.pool.get('hr.employee')
        if context is None:
            context = {}
        hour = (time.mktime(
            time.strptime(data['date'] or time.strftime('%Y-%m-%d %H:%M:%S'),
                          '%Y-%m-%d %H:%M:%S')) - time.mktime(
                              time.strptime(data['date_start'],
                                            '%Y-%m-%d %H:%M:%S'))) / 3600.0
        minimum = data['analytic_amount']
        if minimum:
            hour = round(round((hour + minimum / 2) / minimum) * minimum, 2)
        res = timesheet_obj.default_get(cr,
                                        uid, ['product_id', 'product_uom_id'],
                                        context=context)

        if not res['product_uom_id']:
            raise osv.except_osv(
                _('User Error!'),
                _('Please define cost unit for this employee.'))
        up = timesheet_obj.on_change_unit_amount(
            cr, uid, False, res['product_id'], hour, False,
            res['product_uom_id'])['value']

        res['name'] = data['info']
        res['account_id'] = data['account_id'].id
        res['unit_amount'] = hour
        emp_journal = emp_obj.browse(cr, uid, emp_id,
                                     context=context).journal_id
        res['journal_id'] = emp_journal and emp_journal.id or False
        res.update(up)
        up = timesheet_obj.on_change_account_id(cr, uid, [],
                                                res['account_id']).get(
                                                    'value', {})
        res.update(up)
        return timesheet_obj.create(cr, uid, res, context=context)

    def sign_out_result_end(self, cr, uid, ids, context=None):
        emp_obj = self.pool.get('hr.employee')
        for data in self.browse(cr, uid, ids, context=context):
            emp_id = data.emp_id.id
            emp_obj.attendance_action_change(cr, uid, [emp_id], {
                'action': 'sign_out',
                'action_date': data.date
            })
            self._write(cr, uid, data, emp_id, context=context)
        return {'type': 'ir.actions.act_window_close'}

    def sign_out_result(self, cr, uid, ids, context=None):
        emp_obj = self.pool.get('hr.employee')
        for data in self.browse(cr, uid, ids, context=context):
            emp_id = data.emp_id.id
            emp_obj.attendance_action_change(cr, uid, [emp_id], {
                'action': 'action',
                'action_date': data.date
            })
            self._write(cr, uid, data, emp_id, context=context)
        return {'type': 'ir.actions.act_window_close'}
Beispiel #12
0
class hr_si_project(osv.osv_memory):

    _name = 'hr.sign.in.project'
    _description = 'Sign In By Project'
    _columns = {
        'name':
        fields.char('Employee\'s Name', size=32, readonly=True),
        'state':
        fields.related('emp_id',
                       'state',
                       string='Current Status',
                       type='selection',
                       selection=[('present', 'Present'),
                                  ('absent', 'Absent')],
                       required=True,
                       readonly=True),
        'date':
        fields.datetime('Starting Date'),
        'server_date':
        fields.datetime('Current Date', readonly=True),
        'emp_id':
        fields.many2one('hr.employee', 'Employee ID')
    }

    def view_init(self, cr, uid, fields, context=None):
        """
        This function checks for precondition before wizard executes
        @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 fields: List of fields for default value
        @param context: A standard dictionary for contextual values
        """
        emp_obj = self.pool.get('hr.employee')
        emp_id = emp_obj.search(cr,
                                uid, [('user_id', '=', uid)],
                                context=context)
        if not emp_id:
            raise osv.except_osv(_('User Error!'),
                                 _('Please define employee for your user.'))
        return False

    def check_state(self, cr, uid, ids, context=None):
        obj_model = self.pool.get('ir.model.data')
        emp_id = self.default_get(cr, uid, ['emp_id'], context)['emp_id']
        # get the latest action (sign_in or out) for this employee
        cr.execute(
            'select action from hr_attendance where employee_id=%s and action in (\'sign_in\',\'sign_out\') order by name desc limit 1',
            (emp_id, ))
        res = (cr.fetchone() or ('sign_out', ))[0]
        in_out = (res == 'sign_out') and 'in' or 'out'
        #TODO: invert sign_in et sign_out
        model_data_ids = obj_model.search(
            cr,
            uid, [('model', '=', 'ir.ui.view'),
                  ('name', '=', 'view_hr_timesheet_sign_%s' % in_out)],
            context=context)
        resource_id = obj_model.read(cr,
                                     uid,
                                     model_data_ids,
                                     fields=['res_id'],
                                     context=context)[0]['res_id']
        return {
            'name': _('Sign in / Sign out'),
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'hr.sign.%s.project' % in_out,
            'views': [(resource_id, 'form')],
            'type': 'ir.actions.act_window',
            'target': 'new'
        }

    def sign_in_result(self, cr, uid, ids, context=None):
        emp_obj = self.pool.get('hr.employee')
        for data in self.browse(cr, uid, ids, context=context):
            emp_id = data.emp_id.id
            emp_obj.attendance_action_change(cr, uid, [emp_id], {
                'action': 'sign_in',
                'action_date': data.date
            })
        return {'type': 'ir.actions.act_window_close'}

    def default_get(self, cr, uid, fields_list, context=None):
        res = super(hr_si_project, self).default_get(cr,
                                                     uid,
                                                     fields_list,
                                                     context=context)
        emp_obj = self.pool.get('hr.employee')
        emp_id = emp_obj.search(cr,
                                uid, [('user_id', '=', uid)],
                                context=context)
        if emp_id:
            for employee in emp_obj.browse(cr, uid, emp_id, context=context):
                res.update({
                    'name': employee.name,
                    'state': employee.state,
                    'emp_id': emp_id[0],
                    'server_date': time.strftime('%Y-%m-%d %H:%M:%S')
                })
        return res
Beispiel #13
0
class loewieec_shop(osv.osv):
    _name = 'loewieec.shop'
    _description = u"电商店铺"

    _columns = {
        'active':
        fields.boolean(string='Active', default=False),
        'tmall_time':
        fields.datetime(string='TMall Time'),
        'name':
        fields.char(u'店铺名称', size=16, required=True),
        'code':
        fields.char(u'店铺前缀',
                    size=8,
                    required=True,
                    help=u"系统会自动给该店铺的订单编号.客户昵称加上此前缀.通常同一个平台的店铺前缀设置成一样"),
        'platform':
        fields.selection([
            ('tb', u'淘宝天猫'),
            ('sb', u'淘宝沙箱'),
        ],
                         string=u'电商平台',
                         required=True,
                         help=u"淘宝、京东等电商平台"),
        #'categ_id': fields.many2one('product.category', string=u"商品默认分类", required=True),
        'location_id':
        fields.many2one('stock.location', string=u"店铺库位", required=True),
        'journal_id':
        fields.many2one('account.journal', string=u"默认销售账簿", required=True),
        'post_product_id':
        fields.many2one('product.product', string=u"邮费"),
        #'coupon_product_id': fields.many2one('product.product', string=u"优惠减款", required=True),
        'gift_product_id':
        fields.many2one(
            'product.product',
            string=u"赠品",
        ),
        'partner_id':
        fields.many2one('res.partner', string='Partner', required=True),
        'pricelist_id':
        fields.many2one('product.pricelist',
                        string='Price List',
                        required=True),
        'warehouse_id':
        fields.many2one('stock.warehouse', string='Warehouse', required=True),
        'appkey':
        fields.char(u'App Key', ),
        'appsecret':
        fields.char(u'App Secret', ),
        'sessionkey':
        fields.char(u'Session Key', ),
        'apiurl':
        fields.char(u'API URL', ),
        'authurl':
        fields.char(u'Auth URL', ),
        'tokenurl':
        fields.char(u'Token URL', ),
        'products':
        fields.one2many('product.tmalljd', 'ec_shop_id', string="Products"),
        'orders':
        fields.one2many('sale.order', 'shop_id', string="Orders"),
        'start_modified':
        fields.datetime(string='Start Modified'),
        'end_modified':
        fields.datetime(string='End Modified'),
        'sync_interval':
        fields.integer(u'同步最近多少小时的订单', default=24),
        'import_salesorder':
        fields.many2one('sale.order', u'天猫COE信息的目标订单'),
        'last_log':
        fields.text(u'同步信息'),
        'tmi_state':
        fields.selection([
            ('WAIT_BUYER_PAY', u'等待买家付款'),
            ('WAIT_SELLER_SEND_GOODS', u'等待卖家发货'),
            ('WAIT_BUYER_CONFIRM_GOODS', u'等待买家确认收货'),
            ('TRADE_FINISHED', u'交易成功'),
            ('TRADE_CLOSED', u'交易关闭'),
            ('TRADE_CLOSED_BY_TAOBAO', '交易被淘宝关闭'),
            ('ALL_WAIT_PAY', u'所有买家未付款的交易'),
            ('ALL_CLOSED', u'所有关闭的交易'),
        ],
                         '订单的天猫订单状态',
                         default='WAIT_SELLER_SEND_GOODS'),
    }

    def update_waybill_no_tmall(self, cr, uid, ids, context=None):  #
        port = 80
        shop = self.browse(cr, uid, ids[0], context=context)
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = LogisticsOfflineSendRequest(shop.apiurl, port)
        req.company_code = "EMS"

        sale_id = shop.import_salesorder.id
        domain = [('order_id', '=', sale_id)]
        coe_tmino = self.pool.get('sale.order.line').read_group(
            cr,
            uid,
            domain, ['tmi_jdi_no', 'coe_no'], ['product_id'],
            context=context)
        resp = req.getResponse(shop.sessionkey)
        companies = resp.get('logistics_companies_get_response').get(
            'logistics_companies', False)
        comp_list = companies.get('logistics_company', False)

        return True

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

        port = 80
        shop = self.browse(cr, uid, ids[0], context=context)
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = LogisticsCompaniesGetRequest(shop.apiurl, port)
        req.fields = "id,code,name,reg_mail_no"
        req.order_mode = "all"

        resp = req.getResponse(shop.sessionkey)
        companies = resp.get('logistics_companies_get_response').get(
            'logistics_companies', False)
        comp_list = companies.get('logistics_company', False)

        carrier_obj = self.pool.get('loewie.carrier')
        for comp in comp_list:
            comp_ids = carrier_obj.search(cr,
                                          uid,
                                          [('name', '=', comp.get('name'))],
                                          context=context)
            comp_ids = comp_ids and comp_ids[0] or 0
            if not comp_ids:
                vals = {
                    'name': comp.get('name'),
                    'id_tm': str(comp.get('id')),
                    'code_tm': comp.get('code'),
                    'reg_mail_no': comp.get('reg_mail_no')
                }
                carrier_obj.create(cr, uid, vals, context=context)

        return True

    def set_losgistic_confirm(self,
                              cr,
                              uid,
                              ids,
                              context=None,
                              salesorder=None):  #

        port = 80
        shop = self.browse(cr, uid, ids[0], context=context)
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = LogisticsOnlineConfirmRequest(shop.apiurl, port)

        tmi_jdi_list = {}
        for line in salesorder.order_line:

            tmi_jdi_no, coe_no, is_sent = line.tmi_jdi_no, line.coe_no, line.logistic_sent
            tmi_jdi_no = tmi_jdi_no.strip()
            coe_no = coe_no and coe_no.name.strip() or False
            if not tmi_jdi_no or not coe_no or is_sent: continue
            tmi_jdi_list[tmi_jdi_no] = coe_no

        is_sent_list = []
        for tmi_jdi_num in tmi_jdi_list.keys():
            req.tid = tmi_jdi_num
            req.out_sid = tmi_jdi_list[tmi_jdi_num]
            resp = req.getResponse(shop.sessionkey)
            is_ok = resp.get('logistics_online_confirm_response').get(
                'shipping', False).get('is_success')

            if is_ok:
                is_sent_list.append(tmi_jdi_num)

        for line3 in salesorder.order_line:
            tmi_jdi = line3.tmi_jdi_no
            if tmi_jdi.strip() in is_sent_list:
                line3.logistic_sent = True

        return True

    def get_full_path(self, cr, uid, path):
        # sanitize ath
        path = re.sub('[.]', '', path)
        path = path.strip('/\\')
        return os.path.join(tools.config.filestore(cr.dbname), path)

    def create_order_from_excel(self,
                                cr,
                                uid,
                                ids,
                                coe_lines,
                                product_lines,
                                tmijdi_fname,
                                context=None):
        order_obj = self.pool.get('sale.order')
        shop = self.browse(cr, uid, ids[0], context=context)
        product_gift_id = shop.gift_product_id.id
        partner_id = shop.partner_id.id

        # 检查所有产品名是否 在ERP中有匹配的项
        product_obj = self.pool.get('product.product')
        for product in product_lines:
            product_name = product.get('product', "").strip()
            product_ids = product_obj.search(
                cr,
                uid, [('name_template', '=ilike', product_name)],
                context=context)
            if not product_ids:
                name = self.string_refactor(product_name)
                product_ids = product_obj.search(
                    cr,
                    uid, [('name_template', 'ilike', name)],
                    context=context)
                if product_ids: product['desc'] = u"产品名未能精确匹配"

            if not product_ids:
                raise osv.except_osv(
                    u'Excel产品名错误',
                    u'''无法再ERP中找到 - %s. \r\n请检查名字 并纠正如下情况:\r\n 1. 125 ml -> 125ml. \r\n 2. Eros - Eros Warming - 150ml  -> Eros - Warming - 150ml'''
                    % product_name)
                return False
            product['product_id'] = product_ids[0]

        # 销售订单 值列表
        order_name = tmijdi_fname.strip().split(".")[0]
        order_val = {
            'name': tmijdi_fname.strip().split(".")[0],
            'shop_id': shop.id,
            'date_order': datetime.now(),  #订单支付时间
            'partner_id': partner_id,
            'partner_invoice_id': partner_id,
            'partner_shipping_id': partner_id,
            'warehouse_id': shop.warehouse_id.id,
            'pricelist_id': shop.pricelist_id.id,
            'company_id': 1,
            'all_discounts': 0,
            'picking_policy': 'direct',
            'state': 'draft',
            'user_id': uid,
            'order_policy': 'picking',
            'client_order_ref': order_name,
            'order_line': [],
            'note': '',
        }

        note = ""
        coe_obj = self.pool.get('sale.coe')
        for key in coe_lines:
            coe_line = coe_lines[key]
            coe_vals = { # 为每个收件人 创建COE 条目 		
                'tmi_jdi_no': coe_line["tmi_jdi_no"],
                'name': coe_line["express_no"],
                'name': coe_line["name"],
                'mobile': coe_line["mobile"],
                'state': coe_line["state"],
                'city': coe_line["city"],
                'address': coe_line["address"],
                'zip': coe_line["zip"],
            }
            coe_id = coe_obj.search(cr,
                                    uid,
                                    [('name', '=', coe_line["express_no"])],
                                    context=context)
            if coe_id: coe_id = coe_id[0]
            if not coe_id:
                coe_id = coe_obj.create(cr, uid, coe_vals, context=context)
            coe_line["id"] = coe_id

            gift_product_vals = {   # 为每个 TMI/JDI单 加入一个赠品			
                'product_uos_qty': 1,
                'product_id': product_gift_id,
                'product_uom': 1,
                'express_no': coe_id,
                'price_unit': 0,
                'product_uom_qty': 1,
                'name': '.',
                'delay': 7,
                'discount': 0,
            }
            order_val['order_line'].append((0, 0, gift_product_vals))

            note += u"TMJD NO:%s, COE:%s, 姓名:%s, 电话:%s, 省份:%s, 城市%s, 收货地址:%s, 邮编:%s;" % (
                coe_line["tmi_jdi_no"], coe_line["express_no"],
                coe_line["name"], coe_line["mobile"], coe_line["state"],
                coe_line["city"], coe_line["address"], coe_line["zip"])
            note += chr(10)

        order_val.update({"note": note})

        for o in product_lines:
            desc = o.get('desc', '.').strip()
            if desc == "": desc = '-'
            line_vals = {
                'product_uos_qty': o.get('qty', 0),
                'product_id': o['product_id'],
                'product_uom': 1,
                'express_no': coe_lines[o.get('tmi_jdi_no')]["id"],
                'price_unit': o.get('price', 0),
                'product_uom_qty': o.get('qty', 0),
                'name': desc,
                'delay': 7,
                'discount': 0,
            }
            order_val['order_line'].append((0, 0, line_vals))

        order_id = order_obj.create(cr, uid, order_val, context=context)

        return order_id

    def string_refactor(self, name):

        if not name: return False

        name = name.replace("/", "%")
        name = name.replace("|", "%")
        ll = name.split("-")
        ll = [l.strip() for l in ll]
        ll = "%".join(ll)

        return ll.replace(" ", "%")

    def import_orders_from_excel(self, cr, uid, ids, context=None):
        attachment_obj = self.pool.get('ir.attachment')
        attachment_id = attachment_obj.search(cr,
                                              uid, [('res_id', '=', ids[0])],
                                              context=context)
        if len(attachment_id) < 1: return False

        attach = attachment_obj.browse(cr,
                                       uid,
                                       attachment_id[0],
                                       context=context)
        fname = attach.store_fname
        display_name = attach.name
        if not fname: return False
        fname = self.get_full_path(cr, uid, fname)
        wb = load_workbook(filename=fname)
        #ws = wb.get_sheet_by_name("Sheet1")
        ws = wb.get_sheet_by_name(wb.get_sheet_names()[0])
        highest_row = ws.get_highest_row()
        highest_col = ws.get_highest_column()
        title_order = ws.cell(row=1, column=1).value
        title_product = ws.cell(row=1, column=2).value
        title_qty = ws.cell(row=1, column=3).value
        title_coe = ws.cell(row=1, column=5).value

        if highest_col < 12 or title_order != u"订单編號" or title_product != u"产品名称" or title_coe != u"COE":
            #attach.unlink()
            raise osv.except_osv(u'Excel错误',
                                 u'''文件:%s 格式不正确.''' % display_name)

        row_start = 2
        coe_lines = {}
        last_tmi_jdi_no = None
        last_express_no = None
        while row_start <= highest_row and ws.cell(row=row_start,
                                                   column=2).value:
            tmi_jdi_no = ws.cell(row=row_start, column=1).value
            express_no = ws.cell(row=row_start, column=5).value
            name = ws.cell(row=row_start, column=6).value
            mobile = ws.cell(row=row_start, column=7).value
            address = ws.cell(row=row_start, column=8).value

            if bool(tmi_jdi_no) != bool(express_no):
                #attach.unlink()
                raise osv.except_osv(
                    u'Excel错误', u'''文件'%s'第:%d行不正确地合并单元格.''' %
                    (display_name, row_start + 1))

            if tmi_jdi_no and express_no and name and mobile and address:
                city = ws.cell(row=row_start, column=9).value
                state = ws.cell(row=row_start, column=10).value
                zip = str(ws.cell(row=row_start, column=11).value)
                last_tmi_jdi_no = tmi_jdi_no = str(tmi_jdi_no)
                coe_lines[last_tmi_jdi_no] = {
                    "id": 1,
                    "tmi_jdi_no": tmi_jdi_no,
                    "express_no": express_no,
                    "name": name,
                    "mobile": mobile,
                    "address": address,
                    "city": city,
                    "state": state,
                    "zip": zip
                }

            row_start += 1

        row_start = 2
        product_lines = []
        last_tmi_jdi_no = None
        last_express_no = None
        while row_start <= highest_row and ws.cell(row=row_start,
                                                   column=2).value:
            line = {}
            line["product_id"] = 1
            line["desc"] = ""
            line["product"] = ws.cell(row=row_start, column=2).value
            qty_tmp = ws.cell(row=row_start, column=3)
            line["qty"] = qty_tmp.get_original_value() or 1
            cell_price = ws.cell(row=row_start, column=4)
            price_tmp = cell_price.get_original_value() or 0
            if line["qty"] > 1: price_tmp = price_tmp / line["qty"]
            line["price"] = price_tmp

            tmi_jdi_no = ws.cell(row=row_start, column=1).value
            express_no = ws.cell(row=row_start, column=5).value
            if tmi_jdi_no:
                last_tmi_jdi_no = str(tmi_jdi_no)
                last_express_no = express_no

            line['tmi_jdi_no'] = last_tmi_jdi_no
            line['express_no'] = last_express_no

            product_lines.append(line)
            row_start += 1

        self.create_order_from_excel(cr,
                                     uid,
                                     ids,
                                     coe_lines,
                                     product_lines,
                                     display_name,
                                     context=context)
        attach.unlink()
        return True

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

        port = 80
        shop = self.browse(cr, uid, ids[0], context=context)
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = ItemSkusGetRequest(shop.apiurl, port)
        req.fields = "sku_id, num_iid, properties, price, status, memo, properties_name, outer_id,quantity,barcode,change_prop,sku_spec_id,extra_id"

        if not num_iids:
            req.num_iids = shop.tokenurl
        else:
            req.num_iids = num_iids

        resp = req.getResponse(shop.sessionkey)
        skus = resp.get('item_skus_get_response').get('skus',
                                                      False).get('sku', False)

        return skus

    def create_product_tmalljd_nosku(self, cr, uid, ids, item, context=None):
        product_tmalljd_objs = self.pool.get('product.tmalljd')
        product_vals = {
            'ec_shop_id': ids[0],
            'ec_price': float(item.get('price')),
            'ec_qty': item.get('num'),
            'ec_outer_code': item.get('outer_id'),
            'ec_num_iid': str(item.get('num_iid')),
            'ec_title': item.get('title')
        }

        pids = product_tmalljd_objs.search(
            cr,
            uid, [('ec_num_iid', '=', str(item.get('num_iid'))),
                  ('ec_shop_id', '=', ids[0])],
            context=context)
        if len(pids) < 1:
            product_tmalljd_objs.create(cr, uid, product_vals)
        return True

    def search_product(self, cr, uid, ids, context=None):
        this = self.browse(cr, uid, ids, context=context)[0]
        res = self._search_product(cr,
                                   uid,
                                   ids,
                                   product_name=None,
                                   start_modified=this.start_modified,
                                   end_modified=this.end_modified,
                                   context=context)

        if len(res) < 1: return
        product_tmalljd_objs = self.pool.get('product.tmalljd')
        num_iids = [str(o['num_iid']) for o in res]
        titles = {}
        for item in res:
            titles[str(item.get('num_iid'))] = item.get('title')

        skus_list = []
        skus_list2 = []
        interval = 40
        start = end = 0
        final_end = len(num_iids)

        while start < final_end:
            if start + interval > final_end: end = final_end
            else: end = start + interval
            sub_list = num_iids[start:end]
            sub_num_iids = ",".join(sub_list)
            skus_list += self.search_product_sku(cr,
                                                 uid,
                                                 ids,
                                                 num_iids=sub_num_iids,
                                                 context=context)
            start = end

        for sku_item in skus_list:
            str_num_iid = str(sku_item.get('num_iid'))
            if str_num_iid not in skus_list2:
                skus_list2.append(str_num_iid)

        no_sku_num_iids = []
        for item in res:
            if str(item["num_iid"]) not in skus_list2:
                self.create_product_tmalljd_nosku(cr,
                                                  uid,
                                                  ids,
                                                  item,
                                                  context=context)

        for sku in skus_list:

            product_vals = {
                'ec_shop_id': this.id,
                'ec_price': float(sku.get('price')),
                'ec_qty': sku.get('quantity'),
                'ec_outer_code': sku.get('outer_id'),
                'ec_sku_id': str(sku.get('sku_id'))
            }  #, 'ec_ean13':sku.get('barcode','')}
            num_iid = str(sku['num_iid'])
            product_vals['ec_num_iid'] = num_iid
            product_vals['ec_title'] = titles[num_iid]
            pids = product_tmalljd_objs.search(
                cr,
                uid, [('ec_sku_id', '=', str(sku['sku_id'])),
                      ('ec_shop_id', '=', this.id)],
                context=context)
            #if len(pids)>0:
            #    product_tmalljd_objs.write(cr,uid,pids[0],product_vals)
            #else:
            if len(pids) < 1:
                product_tmalljd_objs.create(cr, uid, product_vals)

        return True

    def _search_product(self,
                        cr,
                        uid,
                        ids,
                        product_name=None,
                        start_modified=None,
                        end_modified=None,
                        context=None):
        """
        1) 按商品名称,商品修改时间搜索店铺商品
        2) start_modified、end_modified 都是UTC时间,需要加上8小时传给电商平台
        """
        shop_id = self.browse(cr, uid, ids[0], context=context)
        setDefaultAppInfo(shop_id.appkey, shop_id.appsecret)
        req = ItemsOnsaleGetRequest(shop_id.apiurl, 80)
        req.fields = "approve_status,num_iid,title,nick,type,num,list_time,price,modified,delist_time,outer_id"
        if product_name:
            req.q = product_name

        req.page_no = 1
        req.page_size = 100
        total_get = 0
        total_results = 100
        res = []
        while total_get < total_results:
            resp = req.getResponse(shop_id.sessionkey)
            total_results = resp.get('items_onsale_get_response').get(
                'total_results')

            if total_results > 0:
                res += resp.get('items_onsale_get_response').get('items').get(
                    'item')
            total_get += req.page_size
            req.page_no = req.page_no + 1
        #
        # 时间需要减去8小时
        for r in res:
            r['modified'] = (datetime.strptime(
                r['modified'],
                '%Y-%m-%d %H:%M:%S',
            ) - timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S')
        return res

    def create_shipping_address(self, cr, uid, partner_id, vals, context=None):

        partner_objs = self.pool.get('res.partner')
        #state_objs = self.pool.get('res.country.state')
        state_id = 0
        if vals.get('state', False):
            state_id = self.pool.get('res.country.state').search(
                cr, uid, [('name', 'like', vals.get('state'))])

        if not partner_id: return 0
        partner_vals = {
            'parent_id': partner_id,
            'name': vals.get('name'),
            'phone': vals.get('phone'),
            'street': vals.get('street'),
            'mobile': vals.get('mobile'),
            'city': vals.get('city'),
            'zip': vals.get('zip'),
            'type': 'delivery',
            'is_company': False,
            'customer': False,
            'supplier': False,
        }

        if state_id:
            partner_vals.update({'state': state_id[0]})

        id = partner_objs.create(cr, uid, partner_vals, context=context)
        return id or 0

    def remove_duplicate_orders(self, cr, uid, orders, context=None):
        sale_obj = self.pool.get('sale.order')
        submitted_references = [o['sale_code'] for o in orders]
        existing_order_ids = sale_obj.search(
            cr, uid, [('name', 'in', submitted_references)], context=context)
        existing_orders = sale_obj.read(cr,
                                        uid,
                                        existing_order_ids, ['name'],
                                        context=context)
        existing_references = set([o['name'] for o in existing_orders])
        orders_to_save = [
            o for o in orders if o['sale_code'] not in existing_references
        ]
        return orders_to_save

    def search_orders_by_modified_time(self,
                                       cr,
                                       uid,
                                       ids,
                                       status='WAIT_SELLER_SEND_GOODS',
                                       date_start=None,
                                       date_end=None,
                                       context=None):
        port = 80
        shop = self.browse(cr, uid, ids[0], context=context)
        partner_id = shop.partner_id.id
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = TradesSoldIncrementGetRequest(shop.apiurl, port)
        req.fields = "type,seller_nick,buyer_nick,created,sid,tid,status,buyer_memo,seller_memo,payment,discount_fee,adjust_fee,post_fee,total_fee, pay_time,end_time,modified,received_payment,price,alipay_id,receiver_name,receiver_state,receiver_city,receiver_district,receiver_address, receiver_zip,receiver_mobile,receiver_phone,orders.price,orders.num,orders.iid,orders.num_iid,orders.sku_id,orders.refund_status,orders.status,orders.oid, orders.total_fee,orders.payment,orders.discount_fee,orders.adjust_fee,orders.sku_properties_name,orders.outer_iid,orders.outer_sku_id"
        req.status = status
        req.type = "instant_trade,auto_delivery,guarantee_trade,tmall_i18n"

        if shop.start_modified:
            req.start_modified = shop.start_modified
        if shop.end_modified:
            req.end_modified = shop.end_modified

        res = []
        req.page_no = 1
        req.page_size = 100

        total_get = 0
        total_results = 100
        while total_get < total_results:
            resp = req.getResponse(shop.sessionkey)
            trades = resp.get('trades_sold_increment_get_response').get(
                'trades', False)
            total_results = resp.get('trades_sold_increment_get_response').get(
                'total_results')
            _logger.info("Jimmy total_results :%d" % total_results)
            if total_results > 0:
                res += trades.get('trade')
            total_get += req.page_size
            req.page_no = req.page_no + 1
            _logger.info("Jimmy page_size :%d" % req.page_size)
            _logger.info("Jimmy total_get :%d" % total_get)
        # 时间需要减去8小时
        # 单号加上店铺前缀
        order_ids = []
        for trade in res:
            trade['created'] = (datetime.strptime(
                trade['created'],
                '%Y-%m-%d %H:%M:%S',
            ) - timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S')
            trade['pay_time'] = (datetime.strptime(
                trade.get('pay_time'),
                '%Y-%m-%d %H:%M:%S',
            ) - timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S')
            trade['sale_code'] = '%s_%s' % (shop.code, trade.get('tid'))

        orders = self.remove_duplicate_orders(cr, uid, res, context=context)
        #orders = res
        for trade in orders:
            #try:
            #    #_logger.info("Jimmy before create_order")
            #order_id = self.create_order(cr, uid, ids, trade, context = context )
            order_id = self.create_order(cr, uid, ids, trade, context=context)
            #    _logger.info("Jimmy after create_order")
            #    order_ids.append(order_id)
            #except Exception, e:
            #    syncerr = u"店铺[%s]订单[%s]同步错误: %s" % (shop.name, trade['tid'], e)
            #    self.pool.get('loewieec.error').create(cr, uid, {'name':syncerr, 'shop_id': shop.id}, context = context )
            #    continue
        return order_ids

    def get_tmall_time(self, cr, uid, ids, context=None):
        shop = self.browse(cr, uid, ids[0], context=context)
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = TimeGetRequest(shop.apiurl, 80)
        resp = req.getResponse(shop.sessionkey)
        ttime = resp.get('time_get_response').get('time', False)

        if ttime:
            shop.tmall_time = ttime
        return True

    def create_order(self, cr, uid, ids, trade, context=None):
        order_obj = self.pool.get('sale.order')
        shop = self.browse(cr, uid, ids[0], context=context)
        partner_id = shop.partner_id.id
        gift_product_id = shop.gift_product_id.id

        order_val = {
            'name':
            "%s_%s" %
            (shop.code,
             self.pool.get('ir.sequence').get(cr, uid, 'sale.order') or '/'),
            'shop_id':
            shop.id,
            'date_order':
            datetime.now(),  #订单支付时间 trade.get('pay_time') or 
            'create_date':
            datetime.now(),  #trade.get('created'),       #订单创建时间
            'partner_id':
            partner_id,
            'partner_invoice_id':
            partner_id,
            'partner_shipping_id':
            partner_id,
            'warehouse_id':
            shop.warehouse_id.id,
            'pricelist_id':
            shop.pricelist_id.id,
            'company_id':
            1,
            'all_discounts':
            0,
            'picking_policy':
            'direct',
            'state':
            'draft',
            'user_id':
            uid,
            'order_policy':
            'picking',
            'client_order_ref':
            u'Loewieec_sync Generated',
            'order_line': [],
        }

        product_null_id = self.pool.get('product.product').search(
            cr, uid, [('name_template', '=', u'刷单空包')], context=context)
        product_null_id = product_null_id and product_null_id[0] or 0
        if not product_null_id:
            raise osv.except_osv(u'ERP错误', u'''ERP中不存在 '刷单空包' 产品!''')

        order_lines = []
        tids = []
        for order in trade:
            tid = str(order['tid'])
            if order['is_jaycee']:
                jaycee_vals = {
                    'product_id': product_null_id,
                    'product_uos_qty': 1,
                    'tmi_jdi_no': tid,
                    'product_uom': 1,
                    'price_unit': 0,
                    'product_uom_qty': 1,
                    'name': '-',
                    'delay': 7,
                    'discount': 0,
                }
                order_val['order_line'].append((0, 0, jaycee_vals))
                continue

            lines = order["orders"]["order"]
            for line in lines:
                order_lines.append(line)
                tids.append(tid)

        for order_line in order_lines:
            tid = str(order_line.get('tid') or order_line.get('oid'))
            line_vals = {
                'product_uos_qty': order_line.get('num'),
                'product_id': 1,
                'tmi_jdi_no': tid,
                'product_uom': 1,
                'price_unit': 1,
                'product_uom_qty': order_line.get('num'),
                'name': '-',
                'delay': 7,
                'discount': 0,
            }
            product_tmalljd_ids = self.pool.get('product.tmalljd').search(
                cr,
                uid, [('ec_sku_id', '=', order_line.get('sku_id')
                       or order_line.get('num_iid'))],
                context=context)

            #如果没有匹配到产品,报同步异常  coe_lines
            if not product_tmalljd_ids:
                syncerr = u"订单导入错误: 匹配不到商品。tid=%s, 商品num_iid=%s, outer_sku_id=%s, sku_id=%s " % (
                    tid, order_line.get(
                        'num_iid', ''), order_line.get(
                            'outer_sku_id', ''), order_line.get('sku_id', ''))
                self.pool.get('loewieec.error').create(cr,
                                                       uid, {
                                                           'name': syncerr,
                                                           'shop_id': shop.id
                                                       },
                                                       context=context)
                return False

            product_tmalljd_obj = self.pool.get('product.tmalljd').browse(
                cr, uid, product_tmalljd_ids[0], context=context)
            product_id = product_tmalljd_obj.erp_product_id.id
            uom_id = product_tmalljd_obj.erp_product_id.uom_id.id
            #添加订单明细行
            price_unit = float(order_line.get(
                'payment', 0)) / order_line.get('num') or float(
                    order_line.get('total_fee', 0)) / order_line.get('num')
            line_vals.update({
                'product_id': product_id,
                'price_unit': price_unit,
                'product_uom': uom_id
            })
            order_val['order_line'].append((0, 0, line_vals))

        for tid in tids:
            gift_vals = {
                'product_uos_qty': 1,
                'product_id': gift_product_id,
                'tmi_jdi_no': tid,
                'product_uom': 1,
                'price_unit': 0,
                'product_uom_qty': 1,
                'name': '.',
                'delay': 7,
                'discount': 0,
            }

            order_val['order_line'].append((0, 0, gift_vals))

        order_id = order_obj.create(cr, uid, order_val, context=context)

        return order_id

    def search_orders_sent_on_tmall(self, cr, uid, ids, context=None):
        return self.search_orders_by_created_time(
            cr,
            uid,
            ids,
            context=context,
            status=['WAIT_BUYER_CONFIRM_GOODS', 'WAIT_SELLER_SEND_GOODS'])

    def search_orders_seller_memo(self, cr, uid, ids, context=None, orders={}):
        port = 80
        shop = self.browse(cr, uid, ids[0], context=context)
        partner_id = shop.partner_id.id
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = TradeGetRequest(shop.apiurl, port)
        req.fields = "seller_memo"

        for order in orders:
            req.tid = order["tid"]
            resp = req.getResponse(shop.sessionkey)
            seller_memo = resp.get('trade_get_response',
                                   '').get('trade', '').get('seller_memo', '')
            order['is_jaycee'] = seller_memo.find(u'jaycee订单') >= 0

        return orders

    def search_orders_by_created_time(self,
                                      cr,
                                      uid,
                                      ids,
                                      context=None,
                                      status=[]):
        port = 80
        shop = self.browse(cr, uid, ids[0], context=context)
        partner_id = shop.partner_id.id
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = TradesSoldGetRequest(shop.apiurl, port)

        req.fields = "sid,tid,receiver_name,receiver_state,receiver_city,receiver_district,receiver_address, receiver_zip,receiver_mobile,receiver_phone,orders.num,orders.store_code,orders.num_iid,orders.sku_id,orders.oid, orders.total_fee,orders.payment,orders.outer_sku_id"
        req.type = "instant_trade,auto_delivery,guarantee_trade,tmall_i18n"
        hours_interval = shop.sync_interval
        if hours_interval: hours_interval -= 8
        else: hours_interval = 16
        req.start_created = (
            datetime.now() -
            timedelta(hours=hours_interval)).strftime('%Y-%m-%d %H:%M:%S')
        req.end_created = (datetime.now() +
                           timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S')

        res = []
        if len(status) < 1:
            status.append(shop.tmi_state or 'WAIT_SELLER_SEND_GOODS')

        for order_status in status:
            req.status = order_status
            req.page_no = 1
            req.page_size = 100
            total_get = 0
            total_results = 100
            while total_get < total_results:
                resp = req.getResponse(shop.sessionkey)
                trades = resp.get('trades_sold_get_response').get(
                    'trades', False)
                total_results = resp.get('trades_sold_get_response').get(
                    'total_results')
                _logger.info("Jimmy total_results :%d" % total_results)
                if total_results > 0:
                    res += trades.get('trade')
                total_get += req.page_size
                req.page_no = req.page_no + 1

        if total_results < 1:
            shop.last_log = u"在%d小时内没有状态:%s 的订单可下载" % (shop.sync_interval,
                                                       shop.tmi_state)
            return True

        orders = self.remove_duplicate_tmi_jdi_no(cr,
                                                  uid,
                                                  ids,
                                                  res,
                                                  shop,
                                                  context=context)
        filtered_orders = self.search_orders_seller_memo(
            cr, uid, ids, context, orders)
        order_id = self.create_order(cr,
                                     uid,
                                     ids,
                                     filtered_orders,
                                     context=context)
        if order_id: shop.import_salesorder = order_id
        return order_id

    def remove_duplicate_tmi_jdi_no(self,
                                    cr,
                                    uid,
                                    ids,
                                    orders,
                                    shop,
                                    context=None):
        statement = "select tmi_jdi_no from sale_order_line where state not in ('cancel','draft') group by tmi_jdi_no"
        cr.execute(statement)
        exist_tmi_jdi_no = []
        res = []
        last_log = []

        for item in cr.fetchall():
            exist_tmi_jdi_no.append(item[0])

        for order in orders:
            if str(order["tid"]) not in exist_tmi_jdi_no:
                res.append(order)
            else:
                last_log.append(str(order["tid"]))
        if len(last_log) > 0:
            shop.last_log = u"以下电商单号ERP中已存在,所以此次未导入: " + chr(10) + ",".join(
                last_log) + chr(10)
        return res

    def search_orders_by_tid(self, cr, uid, ids, context=None):
        port = 80
        shop = self.browse(cr, uid, ids[0], context=context)
        partner_id = shop.partner_id.id
        setDefaultAppInfo(shop.appkey, shop.appsecret)
        req = TradeFullinfoGetRequest(shop.apiurl, port)

        req.fields = "type,receiver_name,receiver_state,receiver_city,receiver_district,receiver_address, receiver_zip,receiver_mobile,receiver_phone"
        req.tid = shop.authurl

        resp = req.getResponse(shop.sessionkey)
        trade = resp.get('trade_fullinfo_get_response').get('trade', False)

        return True

    def import_express_no(self, cr, uid, ids, context=None):
        attachment_obj = self.pool.get('ir.attachment')
        attachment_id = attachment_obj.search(cr,
                                              uid, [('res_id', '=', ids[0])],
                                              context=context)
        if len(attachment_id) < 1: return False
        attach = attachment_obj.browse(cr,
                                       uid,
                                       attachment_id[0],
                                       context=context)
        fname = attach.store_fname
        display_name = attach.name
        if not fname: return False
        fname = self.get_full_path(cr, uid, fname)

        shop = self.browse(cr, uid, ids[0], context=context)
        salesorder = shop.import_salesorder
        if not salesorder:
            raise osv.except_osv(u'错误', u'''请选择一个目标订单来导入COE收货人信息!!!''')

        wb = load_workbook(filename=fname)
        ws = wb.get_sheet_by_name(wb.get_sheet_names()[0])
        highest_row = ws.get_highest_row()
        highest_col = ws.get_highest_column()
        title_order = ws.cell(row=0, column=0).value
        title_coe = ws.cell(row=0, column=1).value
        title_name = ws.cell(row=0, column=2).value

        if highest_col < 10 or title_order != u"參考編號" or title_coe != u"e特快單號" or title_name != u"收件人姓名":
            raise osv.except_osv(u'Excel错误',
                                 u'''文件:%s 格式不正确.''' % display_name)

        row_start = 1
        coe_lines = {}
        note = ""
        while row_start <= highest_row and ws.cell(row=row_start,
                                                   column=0).value:
            tmi_jdi_no = str(ws.cell(row=row_start, column=0).value)
            express_no = ws.cell(row=row_start, column=1).value
            name = ws.cell(row=row_start, column=2).value
            mobile = ws.cell(row=row_start, column=3).value
            address = ws.cell(row=row_start, column=4).value
            city = ws.cell(row=row_start, column=6).value
            state = ws.cell(row=row_start, column=7).value
            zip = str(ws.cell(row=row_start, column=8).value)
            coe_lines[tmi_jdi_no] = {
                "tmi_jdi_no": tmi_jdi_no,
                "name": express_no,
                "name": name,
                "mobile": mobile,
                "address": address,
                "city": city,
                "state": state,
                "zip": zip
            }

            note += u"TMJD NO:%s, COE:%s, 姓名:%s, 电话:%s, 省份:%s, 城市%s, 收货地址:%s, 邮编:%s;" % (
                tmi_jdi_no, express_no, name, mobile, state, city, address,
                zip)
            note += chr(10)

            row_start += 1

        # 从ERP数据库中搜索 是否已存在 COE订单号,如未存在则创建新的COE信息,并将ID赋值到 coe_lines的"id"
        coe_obj = self.pool.get("sale.coe")
        for val in coe_lines.values():
            coe_id = coe_obj.search(cr,
                                    uid, [('name', '=', val["name"])],
                                    context=context)
            coe_id = coe_id and coe_id[0] or 0
            if not coe_id:
                coe_id = coe_obj.create(cr, uid, val, context=context)
            else:
                coe_obj_id = coe_obj.browse(cr, uid, [coe_id], context=context)
                tmp_val = coe_obj_id.tmi_jdi_no
                if tmp_val.strip() != val["tmi_jdi_no"].strip():
                    coe_obj_id.tmi_jdi_no = tmp_val + "," + val["tmi_jdi_no"]
            val["id"] = coe_id

        # 按照销售订单行的 TMall订单号,找到并填写对应的COE单号。
        last_log = []
        for line in salesorder.order_line:
            tmijdino = line.tmi_jdi_no
            if tmijdino not in coe_lines.keys():
                last_log.append(tmijdino)
                continue
            line.express_no = coe_lines[tmijdino]["id"]

        # 通知信息
        if len(last_log) > 0:
            shop.last_log = ",".join(
                last_log) + u" - COE-e特快excel文件中不存在以上TMI单号."

        salesorder.note = note
        attach.unlink()
        return True
Beispiel #14
0
class magento_storeview(orm.Model):
    _name = 'magento.storeview'
    _inherit = 'magento.binding'
    _description = "Magento Storeview"

    _order = 'sort_order ASC, id ASC'

    _columns = {
        'name':
        fields.char('Name', required=True, readonly=True),
        'code':
        fields.char('Code', readonly=True),
        'enabled':
        fields.boolean('Enabled', readonly=True),
        'sort_order':
        fields.integer('Sort Order', readonly=True),
        'store_id':
        fields.many2one('magento.store',
                        'Store',
                        ondelete='cascade',
                        readonly=True),
        'lang_id':
        fields.many2one('res.lang', 'Language'),
        'backend_id':
        fields.related('store_id',
                       'website_id',
                       'backend_id',
                       type='many2one',
                       relation='magento.backend',
                       string='Magento Backend',
                       store=True,
                       readonly=True),
        'import_orders_from_date':
        fields.datetime(
            'Import sale orders from date',
            help='do not consider non-imported sale orders before this date. '
            'Leave empty to import all sale orders'),
        'no_sales_order_sync':
        fields.boolean('No Sales Order Synchronization',
                       help='Check if the storeview is active in Magento '
                       'but its sales orders should not be imported.'),
    }

    _defaults = {
        'no_sales_order_sync': False,
    }

    _sql_constraints = [
        ('magento_uniq', 'unique(backend_id, magento_id)',
         'A storeview with same ID on Magento already exists.'),
    ]

    def import_sale_orders(self, cr, uid, ids, context=None):
        session = ConnectorSession(cr, uid, context=context)
        import_start_time = datetime.now()
        for storeview in self.browse(cr, uid, ids, context=context):
            if storeview.no_sales_order_sync:
                _logger.debug("The storeview '%s' is active in Magento "
                              "but its sales orders should not be imported." %
                              storeview.name)
                continue
            backend_id = storeview.backend_id.id
            if storeview.import_orders_from_date:
                from_date = datetime.strptime(
                    storeview.import_orders_from_date,
                    DEFAULT_SERVER_DATETIME_FORMAT)
            else:
                from_date = None
            sale_order_import_batch.delay(
                session,
                'magento.sale.order',
                backend_id, {
                    'magento_storeview_id': storeview.magento_id,
                    'from_date': from_date,
                    'to_date': import_start_time
                },
                priority=1)  # executed as soon as possible
        # Records from Magento are imported based on their `created_at`
        # date.  This date is set on Magento at the beginning of a
        # transaction, so if the import is run between the beginning and
        # the end of a transaction, the import of a record may be
        # missed.  That's why we add a small buffer back in time where
        # the eventually missed records will be retrieved.  This also
        # means that we'll have jobs that import twice the same records,
        # but this is not a big deal because the sales orders will be
        # imported the first time and the jobs will be skipped on the
        # subsequent imports
        next_time = import_start_time - timedelta(seconds=IMPORT_DELTA_BUFFER)
        next_time = next_time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        self.write(cr,
                   uid,
                   ids, {'import_orders_from_date': next_time},
                   context=context)
        return True
Beispiel #15
0
class magento_backend(orm.Model):
    _name = 'magento.backend'
    _description = 'Magento Backend'
    _inherit = 'connector.backend'

    _backend_type = 'magento'

    def select_versions(self, cr, uid, context=None):
        """ Available versions in the backend.

        Can be inherited to add custom versions.  Using this method
        to add a version from an ``_inherit`` does not constrain
        to redefine the ``version`` field in the ``_inherit`` model.
        """
        return [('1.7', '1.7')]

    def _select_versions(self, cr, uid, context=None):
        """ Available versions in the backend.

        If you want to add a version, do not override this
        method, but ``select_version``.
        """
        return self.select_versions(cr, uid, context=context)

    def _get_stock_field_id(self, cr, uid, context=None):
        field_ids = self.pool.get('ir.model.fields').search(
            cr,
            uid, [('model', '=', 'product.product'),
                  ('name', '=', 'virtual_available')],
            context=context)
        return field_ids[0]

    _columns = {
        'version':
        fields.selection(_select_versions, string='Version', required=True),
        'location':
        fields.char('Location',
                    required=True,
                    help="Url to magento application"),
        'admin_location':
        fields.char('Admin Location'),
        'use_custom_api_path':
        fields.boolean(
            'Custom Api Path',
            help="The default API path is '/index.php/api/xmlrpc'. "
            "Check this box if you use a custom API path, in that case, "
            "the location has to be completed with the custom API path "),
        'username':
        fields.char('Username', help="Webservice user"),
        'password':
        fields.char('Password', help="Webservice password"),
        'use_auth_basic':
        fields.boolean(
            'Use HTTP Auth Basic',
            help="Use a Basic Access Authentication for the API. "
            "The Magento server could be configured to restrict access "
            "using a HTTP authentication based on a username and "
            "a password."),
        'auth_basic_username':
        fields.char(
            'Basic Auth. Username',
            help="Basic access authentication web server side username"),
        'auth_basic_password':
        fields.char(
            'Basic Auth. Password',
            help="Basic access authentication web server side password"),
        'sale_prefix':
        fields.char(
            'Sale Prefix',
            help="A prefix put before the name of imported sales orders.\n"
            "For instance, if the prefix is 'mag-', the sales "
            "order 100000692 in Magento, will be named 'mag-100000692' "
            "in OpenERP."),
        'warehouse_id':
        fields.many2one('stock.warehouse',
                        'Warehouse',
                        required=True,
                        help='Warehouse used to compute the '
                        'stock quantities.'),
        'website_ids':
        fields.one2many('magento.website',
                        'backend_id',
                        string='Website',
                        readonly=True),
        'default_lang_id':
        fields.many2one(
            'res.lang',
            'Default Language',
            help="If a default language is selected, the records "
            "will be imported in the translation of this language.\n"
            "Note that a similar configuration exists "
            "for each storeview."),
        'default_category_id':
        fields.many2one(
            'product.category',
            string='Default Product Category',
            help='If a default category is selected, products imported '
            'without a category will be linked to it.'),

        # add a field `auto_activate` -> activate a cron
        'import_products_from_date':
        fields.datetime('Import products from date'),
        'import_categories_from_date':
        fields.datetime('Import categories from date'),
        'catalog_price_tax_included':
        fields.boolean('Prices include tax'),
        'product_stock_field_id':
        fields.many2one(
            'ir.model.fields',
            string='Stock Field',
            domain="[('model', 'in', ['product.product', 'product.template']),"
            " ('ttype', '=', 'float')]",
            help="Choose the field of the product which will be used for "
            "stock inventory updates.\nIf empty, Quantity Available "
            "is used."),
        'product_binding_ids':
        fields.one2many('magento.product.product',
                        'backend_id',
                        string='Magento Products',
                        readonly=True),
    }

    _defaults = {
        'product_stock_field_id': _get_stock_field_id,
        'use_custom_api_path': False,
        'use_auth_basic': False,
    }

    _sql_constraints = [('sale_prefix_uniq', 'unique(sale_prefix)',
                         "A backend with the same sale prefix already exists")]

    def check_magento_structure(self, cr, uid, ids, context=None):
        """ Used in each data import.

        Verify if a website exists for each backend before starting the import.
        """
        for backend_id in ids:
            website_ids = self.pool['magento.website'].search(
                cr, uid, [('backend_id', '=', backend_id)], context=context)
            if not website_ids:
                self.synchronize_metadata(cr, uid, backend_id, context=context)
        return True

    def synchronize_metadata(self, cr, uid, ids, context=None):
        if not hasattr(ids, '__iter__'):
            ids = [ids]
        session = ConnectorSession(cr, uid, context=context)
        for backend_id in ids:
            for model in ('magento.website', 'magento.store',
                          'magento.storeview'):
                # import directly, do not delay because this
                # is a fast operation, a direct return is fine
                # and it is simpler to import them sequentially
                import_batch(session, model, backend_id)

        return True

    def import_partners(self, cr, uid, ids, context=None):
        """ Import partners from all websites """
        if not hasattr(ids, '__iter__'):
            ids = [ids]
        self.check_magento_structure(cr, uid, ids, context=context)
        for backend in self.browse(cr, uid, ids, context=context):
            for website in backend.website_ids:
                website.import_partners()
        return True

    def import_sale_orders(self, cr, uid, ids, context=None):
        """ Import sale orders from all store views """
        if not hasattr(ids, '__iter__'):
            ids = [ids]
        storeview_obj = self.pool.get('magento.storeview')
        storeview_ids = storeview_obj.search(cr,
                                             uid, [('backend_id', 'in', ids)],
                                             context=context)
        storeviews = storeview_obj.browse(cr,
                                          uid,
                                          storeview_ids,
                                          context=context)
        for storeview in storeviews:
            storeview.import_sale_orders()
        return True

    def import_customer_groups(self, cr, uid, ids, context=None):
        if not hasattr(ids, '__iter__'):
            ids = [ids]
        self.check_magento_structure(cr, uid, ids, context=context)
        session = ConnectorSession(cr, uid, context=context)
        for backend_id in ids:
            import_batch.delay(session, 'magento.res.partner.category',
                               backend_id)

        return True

    def _import_from_date(self,
                          cr,
                          uid,
                          ids,
                          model,
                          from_date_field,
                          context=None):
        if not hasattr(ids, '__iter__'):
            ids = [ids]
        self.check_magento_structure(cr, uid, ids, context=context)
        session = ConnectorSession(cr, uid, context=context)
        import_start_time = datetime.now()
        for backend in self.browse(cr, uid, ids, context=context):
            from_date = getattr(backend, from_date_field)
            if from_date:
                from_date = datetime.strptime(from_date,
                                              DEFAULT_SERVER_DATETIME_FORMAT)
            else:
                from_date = None
            import_batch.delay(session,
                               model,
                               backend.id,
                               filters={
                                   'from_date': from_date,
                                   'to_date': import_start_time
                               })
        # Records from Magento are imported based on their `created_at`
        # date.  This date is set on Magento at the beginning of a
        # transaction, so if the import is run between the beginning and
        # the end of a transaction, the import of a record may be
        # missed.  That's why we add a small buffer back in time where
        # the eventually missed records will be retrieved.  This also
        # means that we'll have jobs that import twice the same records,
        # but this is not a big deal because they will be skipped when
        # the last `sync_date` is the same.
        next_time = import_start_time - timedelta(seconds=IMPORT_DELTA_BUFFER)
        next_time = next_time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        self.write(cr, uid, ids, {from_date_field: next_time}, context=context)

    def import_product_categories(self, cr, uid, ids, context=None):
        self._import_from_date(cr,
                               uid,
                               ids,
                               'magento.product.category',
                               'import_categories_from_date',
                               context=context)
        return True

    def import_product_product(self, cr, uid, ids, context=None):
        self._import_from_date(cr,
                               uid,
                               ids,
                               'magento.product.product',
                               'import_products_from_date',
                               context=context)
        return True

    def update_product_stock_qty(self, cr, uid, ids, context=None):
        if not hasattr(ids, '__iter__'):
            ids = [ids]
        mag_product_obj = self.pool.get('magento.product.product')
        product_ids = mag_product_obj.search(cr,
                                             uid,
                                             [('backend_id', 'in', ids),
                                              ('no_stock_sync', '=', False)],
                                             context=context)
        mag_product_obj.recompute_magento_qty(cr,
                                              uid,
                                              product_ids,
                                              context=context)
        return True

    def _magento_backend(self, cr, uid, callback, domain=None, context=None):
        if domain is None:
            domain = []
        ids = self.search(cr, uid, domain, context=context)
        if ids:
            callback(cr, uid, ids, context=context)

    def _scheduler_import_sale_orders(self,
                                      cr,
                                      uid,
                                      domain=None,
                                      context=None):
        self._magento_backend(cr,
                              uid,
                              self.import_sale_orders,
                              domain=domain,
                              context=context)

    def _scheduler_import_customer_groups(self,
                                          cr,
                                          uid,
                                          domain=None,
                                          context=None):
        self._magento_backend(cr,
                              uid,
                              self.import_customer_groups,
                              domain=domain,
                              context=context)

    def _scheduler_import_partners(self, cr, uid, domain=None, context=None):
        self._magento_backend(cr,
                              uid,
                              self.import_partners,
                              domain=domain,
                              context=context)

    def _scheduler_import_product_categories(self,
                                             cr,
                                             uid,
                                             domain=None,
                                             context=None):
        self._magento_backend(cr,
                              uid,
                              self.import_product_categories,
                              domain=domain,
                              context=context)

    def _scheduler_import_product_product(self,
                                          cr,
                                          uid,
                                          domain=None,
                                          context=None):
        self._magento_backend(cr,
                              uid,
                              self.import_product_product,
                              domain=domain,
                              context=context)

    def _scheduler_update_product_stock_qty(self,
                                            cr,
                                            uid,
                                            domain=None,
                                            context=None):
        self._magento_backend(cr,
                              uid,
                              self.update_product_stock_qty,
                              domain=domain,
                              context=context)

    def output_recorder(self, cr, uid, ids, context=None):
        """ Utility method to output a file containing all the recorded
        requests / responses with Magento.  Used to generate test data.
        Should be called with ``erppeek`` for instance.
        """
        from .unit.backend_adapter import output_recorder
        import os
        import tempfile
        fmt = '%Y-%m-%d-%H-%M-%S'
        timestamp = datetime.now().strftime(fmt)
        filename = 'output_%s_%s' % (cr.dbname, timestamp)
        path = os.path.join(tempfile.gettempdir(), filename)
        output_recorder(path)
        return path
Beispiel #16
0
class magento_website(orm.Model):
    _name = 'magento.website'
    _inherit = 'magento.binding'
    _description = 'Magento Website'

    _order = 'sort_order ASC, id ASC'

    _columns = {
        'name':
        fields.char('Name', required=True, readonly=True),
        'code':
        fields.char('Code', readonly=True),
        'sort_order':
        fields.integer('Sort Order', readonly=True),
        'store_ids':
        fields.one2many('magento.store',
                        'website_id',
                        string="Stores",
                        readonly=True),
        'import_partners_from_date':
        fields.datetime('Import partners from date'),
        'product_binding_ids':
        fields.many2many('magento.product.product',
                         string='Magento Products',
                         readonly=True),
    }

    _sql_constraints = [
        ('magento_uniq', 'unique(backend_id, magento_id)',
         'A website with the same ID on Magento already exists.'),
    ]

    def import_partners(self, cr, uid, ids, context=None):
        if not hasattr(ids, '__iter__'):
            ids = [ids]
        session = ConnectorSession(cr, uid, context=context)
        import_start_time = datetime.now()
        for website in self.browse(cr, uid, ids, context=context):
            backend_id = website.backend_id.id
            if website.import_partners_from_date:
                from_date = datetime.strptime(
                    website.import_partners_from_date,
                    DEFAULT_SERVER_DATETIME_FORMAT)
            else:
                from_date = None
            partner_import_batch.delay(
                session, 'magento.res.partner', backend_id, {
                    'magento_website_id': website.magento_id,
                    'from_date': from_date,
                    'to_date': import_start_time
                })
        # Records from Magento are imported based on their `created_at`
        # date.  This date is set on Magento at the beginning of a
        # transaction, so if the import is run between the beginning and
        # the end of a transaction, the import of a record may be
        # missed.  That's why we add a small buffer back in time where
        # the eventually missed records will be retrieved.  This also
        # means that we'll have jobs that import twice the same records,
        # but this is not a big deal because they will be skipped when
        # the last `sync_date` is the same.
        next_time = import_start_time - timedelta(seconds=IMPORT_DELTA_BUFFER)
        next_time = next_time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        self.write(cr,
                   uid,
                   ids, {'import_partners_from_date': next_time},
                   context=context)
        return True
Beispiel #17
0
class project_task_work(orm.Model):
    _inherit = 'project.task.work'

    def _get_display_button(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for work_data in self.browse(cr, uid, ids, context=context):
            res[work_data.id] = False

            if work_data.type_id:
                pt_obj = self.pool.get('accreditation.task.work.type')
                pt_data = pt_obj.browse(cr, uid, work_data.type_id.id)

                if pt_data.create_audit \
                    or pt_data.create_line_to_invoice \
                    or pt_data.create_quotation \
                    or pt_data.create_purchase_requisition \
                    or pt_data.create_sale_quotation \
                    or pt_data.update_agenda \
                    or pt_data.accreditation_request_generation \
                    or pt_data.set_obtained_accreditation \
                    or pt_data.del_obtained_accreditation \
                    or pt_data.create_maintenance_fee_tasks \
                    or pt_data.create_maintenance_fee_offer \
                    or pt_data.create_child_project \
                    or pt_data.get_accreditation_test \
                    or pt_data.req_supervision \
                    or pt_data.doclite_action:

                    res[work_data.id] = True
        return res

    def _display_date_obtained_accreditation(self,
                                             cr,
                                             uid,
                                             ids,
                                             name,
                                             arg,
                                             context=None):
        res = {}
        for work_data in self.browse(cr, uid, ids, context=context):
            res[work_data.id] = False
            if work_data.type_id and work_data.type_id.set_obtained_accreditation:
                res[work_data.id] = True
        return res

    _columns = {
        'type_id':
        fields.many2one('accreditation.task.work.type',
                        'Type of work',
                        ondelete="cascade"),
        'description':
        fields.text('Description'),
        'phase_id':
        fields.related('task_id',
                       'phase_id',
                       type="many2one",
                       relation="project.phase",
                       string='Audit',
                       store=False),
        'department_id':
        fields.related('task_id',
                       'project_id',
                       'analytic_account_id',
                       'department_id',
                       type="many2one",
                       relation="hr.department",
                       string='Dipartimento',
                       store=False),
        'project_state':
        fields.related('task_id',
                       'project_id',
                       'state',
                       type="char",
                       relation="project.project",
                       string='Project State',
                       store=False),
        'project_task_planned_hours':
        fields.related('task_id',
                       'planned_hours',
                       type="float",
                       relation="project.task",
                       string='Task Planned Hours',
                       store=False),
        'project_task_effective_hours':
        fields.related('task_id',
                       'effective_hours',
                       type="float",
                       relation="project.task",
                       string='Task Effective Hours',
                       store=False),
        'not_billing':
        fields.boolean('Not Billing'),
        'project_task_state':
        fields.related('task_id',
                       'state',
                       type="char",
                       relation="project.task",
                       string='Task State',
                       store=False),
        'person_id':
        fields.many2one('res.partner',
                        domain=[
                            ('individual', '=', True),
                        ],
                        string='Persona Fisica'),
        'customer_order_reference':
        fields.char('Riferimento ordine cliente', size=64),
        'meeting_id':
        fields.many2one('calendar.event', 'Meeting'),
        'unit_id':
        fields.many2one('accreditation.units', 'Unità'),
        'date_end':
        fields.date('Data Finale'),
        'audit_visit_doc_review':
        fields.boolean('Attività di Visita/Esame documentale'),
        'audit_visit_accompaniment':
        fields.boolean('Attività di Visita in Accompagnamento'),
        'display_button':
        fields.function(_get_display_button,
                        type='boolean',
                        string="Hidden",
                        store=False),
        'display_date_obtained_accreditation':
        fields.function(_display_date_obtained_accreditation,
                        type='boolean',
                        string="Hidden",
                        store=False),
        'date_obtained_accreditation':
        fields.date('Data di Accreditamento'),
        'exec_date':
        fields.datetime('Data e Ora Esecuzione'),
        'last_protocol':
        fields.char(size=100, string='Ultimo Protocollo'),
    }

    _defaults = {
        'date': None,
        'date_obtained_accreditation': None,
    }

    def onchange_project(self,
                         cr,
                         uid,
                         ids,
                         project_id,
                         task_id,
                         context=None):

        if task_id and context:
            if not context.get('wiew_task_form', False):
                return {
                    'value': {
                        'task_id': None,
                        'unit_id': None,
                    }
                }
        return {
            'value': {
                'unit_id': None,
            }
        }

    def onchange_type_id(self, cr, uid, ids, type_id, context=None):
        if type_id:
            pt_obj = self.pool.get('accreditation.task.work.type')
            pt_data = pt_obj.browse(cr, uid, type_id)

            t_display_button = False
            if pt_data.create_audit \
              or pt_data.create_line_to_invoice \
              or pt_data.create_quotation \
              or pt_data.create_purchase_requisition \
              or pt_data.create_sale_quotation \
              or pt_data.update_agenda \
              or pt_data.accreditation_request_generation \
              or pt_data.set_obtained_accreditation \
              or pt_data.del_obtained_accreditation \
              or pt_data.create_maintenance_fee_tasks \
              or pt_data.create_maintenance_fee_offer \
              or pt_data.create_child_project \
              or pt_data.get_accreditation_test \
              or pt_data.req_supervision \
              or pt_data.doclite_action:
                t_display_button = True

            return {
                'value': {
                    'audit_visit_doc_review': pt_data.audit_visit_doc_review,
                    'audit_visit_accompaniment':
                    pt_data.audit_visit_accompaniment,
                    'display_button': t_display_button,
                }
            }
        return {
            'value': {
                'audit_visit_doc_review': None,
                'audit_visit_accompaniment': None,
                'display_button': False,
            }
        }

    def duplicate_work(self, cr, uid, ids, default={}, context=None):
        context = context or {}
        if default is None:
            default = {}
        default.update({
            'date_end': None,
            'date': None,
            'exec_date': None,
        })
        t_person = default.get('person_id')
        context.update({'person_id': t_person})
        res = super(project_task_work,
                    self).duplicate_work(cr, uid, ids, default, context)
        return res

    def copy(self, cr, uid, ids, default=None, context=None):
        context = context or {}
        if default is None:
            default = {}
        default.update({
            'date_end': None,
            'date': None,
            'exec_date': None,
        })
        res = super(project_task_work, self).copy(cr, uid, ids, default,
                                                  context)
        return res

    def save_work_and_next(self, cr, uid, ids, default={}, context=None):

        if context is None:
            context = {}

        super(project_task_work, self).write(cr, uid, ids, default, context)

        mod_obj = self.pool.get('ir.model.data')
        result = mod_obj.get_object_reference(
            cr, uid, 'project_accredia',
            'view_project_task_work_form_accredia')
        view_id = result and result[1] or False
        return {
            'name': _('Add New Work'),
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'project.task.work',
            'type': 'ir.actions.act_window',
            'context': context,
            'view_id': view_id,
            'target': 'new',
        }

    def save_work(self, cr, uid, ids, default={}, context=None):

        if context is None:
            context = {}
        res = super(project_task_work, self).write(cr, uid, ids, default,
                                                   context)

        t_date = self.browse(cr, uid, ids[0]).date
        if t_date:
            context.update({'day': t_date[:10]})
        t_user_id = default.get('user_id')
        context.update({'user_id': t_user_id})

        t_flag = default.get('default_day_works_flag') or default.get(
            'day_works_flag')

        if t_flag:
            return self.pool.get('wizard.select.date').view_day_works(
                cr, uid, ids, context)

        return res

    def save_work_complete_task(self, cr, uid, ids, default={}, context=None):
        if context is None:
            context = {}
        res = super(project_task_work, self).write(cr, uid, ids, default,
                                                   context)
        value = self.browse(cr, uid, ids)[0]
        t_task = value.task_id.id
        task_obj = self.pool.get('project.task')
        data = task_obj.browse(cr, uid, [t_task])
        if data and data[0]:
            # task_obj._check_child_task(cr, uid, ids, context=context)
            task_obj.case_close(cr, uid, [t_task], context=context)

        t_date = self.browse(cr, uid, ids[0]).date
        context.update({'day': t_date and t_date[:10] or None})
        t_user_id = default.get('user_id')
        context.update({'user_id': t_user_id})

        t_flag = default.get('default_day_works_flag') or default.get(
            'day_works_flag')

        if t_flag:
            return self.pool.get('wizard.select.date').view_day_works(
                cr, uid, ids, context)

        return res

    # a seconda del flag di not_billing. Il controllo non viene
    # effettuato se il lavoro è di tipo
    # ZZ che serve per gestire il pregresso id=30    utilizzo l'id perchè
    # da vals ho solo l'id

    def onchange_task(self, cr, uid, ids, task_id, context=None):
        if not task_id:
            return {}
        task_data = self.pool.get('project.task').browse(cr, uid, task_id)
        t_task_planned = task_data.planned_hours
        t_task_effective = task_data.effective_hours

        return {
            'value': {
                'project_task_planned_hours': t_task_planned,
                'project_task_effective_hours': t_task_effective,
            }
        }
        return {}

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {}
        ctx = context.copy()
        if not context.get('no_analytic_entry', False):
            ctx.update({'no_analytic_entry': True})

        task_res = super(project_task_work, self).create(cr,
                                                         uid,
                                                         vals,
                                                         context=ctx)
        return task_res

    def name_get(self, cr, uid, ids, context=None):
        if not len(ids):
            return []
        res = []
        for data in self.browse(cr, uid, ids):
            t_date = data.date or ''
            descr = ("%s %s") % (data.name, t_date)
            if not data.name:
                if data.type_id and data.type_id.name:
                    descr = ("%s %s") % (data.type_id.name, t_date)

            res.append((data.id, descr))
        return res
Beispiel #18
0
class hr_holidays(osv.osv):
    _name = "hr.holidays"
    _description = "Leave"
    _order = "type desc, date_from asc"
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    _track = {
        'state': {
            'hr_holidays.mt_holidays_approved': lambda self, cr, uid, obj, ctx=None: obj.state == 'validate',
            'hr_holidays.mt_holidays_refused': lambda self, cr, uid, obj, ctx=None: obj.state == 'refuse',
            'hr_holidays.mt_holidays_confirmed': lambda self, cr, uid, obj, ctx=None: obj.state == 'confirm',
        },
    }

    def _employee_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

    def _compute_number_of_days(self, cr, uid, ids, name, args, context=None):
        result = {}
        for hol in self.browse(cr, uid, ids, context=context):
            if hol.type=='remove':
                result[hol.id] = -hol.number_of_days_temp
            else:
                result[hol.id] = hol.number_of_days_temp
        return result

    def _get_can_reset(self, cr, uid, ids, name, arg, context=None):
        """User can reset a leave request if it is its own leave request or if
        he is an Hr Manager. """
        user = self.pool['res.users'].browse(cr, uid, uid, context=context)
        group_hr_manager_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_hr_manager')[1]
        if group_hr_manager_id in [g.id for g in user.groups_id]:
            return dict.fromkeys(ids, True)
        result = dict.fromkeys(ids, False)
        for holiday in self.browse(cr, uid, ids, context=context):
            if holiday.employee_id and holiday.employee_id.user_id and holiday.employee_id.user_id.id == uid:
                result[holiday.id] = True
        return result

    def _check_date(self, cr, uid, ids, context=None):
        for holiday in self.browse(cr, uid, ids, context=context):
            domain = [
                ('date_from', '<=', holiday.date_to),
                ('date_to', '>=', holiday.date_from),
                ('employee_id', '=', holiday.employee_id.id),
                ('id', '!=', holiday.id),
                ('type', '=', holiday.type),
                ('state', 'not in', ['cancel', 'refuse']),
            ]
            nholidays = self.search_count(cr, uid, domain, context=context)
            if nholidays:
                return False
        return True

    _check_holidays = lambda self, cr, uid, ids, context=None: self.check_holidays(cr, uid, ids, context=context)

    _columns = {
        'name': fields.char('Description', size=64),
        'state': fields.selection([('draft', 'To Submit'), ('cancel', 'Cancelled'),('confirm', 'To Approve'), ('refuse', 'Refused'), ('validate1', 'Second Approval'), ('validate', 'Approved')],
            'Status', readonly=True, track_visibility='onchange', copy=False,
            help='The status is set to \'To Submit\', when a holiday request is created.\
            \nThe status is \'To Approve\', when holiday request is confirmed by user.\
            \nThe status is \'Refused\', when holiday request is refused by manager.\
            \nThe status is \'Approved\', when holiday request is approved by manager.'),
        'user_id':fields.related('employee_id', 'user_id', type='many2one', relation='res.users', string='User', store=True),
        'date_from': fields.datetime('Start Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, select=True, copy=False),
        'date_to': fields.datetime('End Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, copy=False),
        'holiday_status_id': fields.many2one("hr.holidays.status", "Leave Type", required=True,readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
        'employee_id': fields.many2one('hr.employee', "Employee", select=True, invisible=False, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
        'manager_id': fields.many2one('hr.employee', 'First Approval', invisible=False, readonly=True, copy=False,
                                      help='This area is automatically filled by the user who validate the leave'),
        'notes': fields.text('Reasons',readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
        'number_of_days_temp': fields.float('Allocation', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, copy=False),
        'number_of_days': fields.function(_compute_number_of_days, string='Number of Days', store=True),
        'meeting_id': fields.many2one('calendar.event', 'Meeting'),
        'type': fields.selection([('remove','Leave Request'),('add','Allocation Request')], 'Request Type', required=True, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, help="Choose 'Leave Request' if someone wants to take an off-day. \nChoose 'Allocation Request' if you want to increase the number of leaves available for someone", select=True),
        'parent_id': fields.many2one('hr.holidays', 'Parent'),
        'linked_request_ids': fields.one2many('hr.holidays', 'parent_id', 'Linked Requests',),
        'department_id':fields.related('employee_id', 'department_id', string='Department', type='many2one', relation='hr.department', readonly=True, store=True),
        'category_id': fields.many2one('hr.employee.category', "Employee Tag", help='Category of Employee', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
        'holiday_type': fields.selection([('employee','By Employee'),('category','By Employee Tag')], 'Allocation Mode', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, help='By Employee: Allocation/Request for individual Employee, By Employee Tag: Allocation/Request for group of employees in category', required=True),
        'manager_id2': fields.many2one('hr.employee', 'Second Approval', readonly=True, copy=False,
                                       help='This area is automaticly filled by the user who validate the leave with second level (If Leave type need second validation)'),
        'double_validation': fields.related('holiday_status_id', 'double_validation', type='boolean', relation='hr.holidays.status', string='Apply Double Validation'),
        'can_reset': fields.function(
            _get_can_reset,
            type='boolean'),
    }
    _defaults = {
        'employee_id': _employee_get,
        'state': 'confirm',
        'type': 'remove',
        'user_id': lambda obj, cr, uid, context: uid,
        'holiday_type': 'employee'
    }
    _constraints = [
        (_check_date, 'You can not have 2 leaves that overlaps on same day!', ['date_from','date_to']),
        (_check_holidays, 'The number of remaining leaves is not sufficient for this leave type', ['state','number_of_days_temp'])
    ] 
    
    _sql_constraints = [
        ('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", 
         "The employee or employee category of this request is missing. Please make sure that your user login is linked to an employee."),
        ('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be anterior to the end date."),
        ('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0."),
    ]

    def _create_resource_leave(self, cr, uid, leaves, context=None):
        '''This method will create entry in resource calendar leave object at the time of holidays validated '''
        obj_res_leave = self.pool.get('resource.calendar.leaves')
        for leave in leaves:
            vals = {
                'name': leave.name,
                'date_from': leave.date_from,
                'holiday_id': leave.id,
                'date_to': leave.date_to,
                'resource_id': leave.employee_id.resource_id.id,
                'calendar_id': leave.employee_id.resource_id.calendar_id.id
            }
            obj_res_leave.create(cr, uid, vals, context=context)
        return True

    def _remove_resource_leave(self, cr, uid, ids, context=None):
        '''This method will create entry in resource calendar leave object at the time of holidays cancel/removed'''
        obj_res_leave = self.pool.get('resource.calendar.leaves')
        leave_ids = obj_res_leave.search(cr, uid, [('holiday_id', 'in', ids)], context=context)
        return obj_res_leave.unlink(cr, uid, leave_ids, context=context)

    def onchange_type(self, cr, uid, ids, holiday_type, employee_id=False, context=None):
        result = {}
        if holiday_type == 'employee' and not employee_id:
            ids_employee = self.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
            if ids_employee:
                result['value'] = {
                    'employee_id': ids_employee[0]
                }
        elif holiday_type != 'employee':
            result['value'] = {
                    'employee_id': False
                }
        return result

    def onchange_employee(self, cr, uid, ids, employee_id):
        result = {'value': {'department_id': False}}
        if employee_id:
            employee = self.pool.get('hr.employee').browse(cr, uid, employee_id)
            result['value'] = {'department_id': employee.department_id.id}
        return result

    # TODO: can be improved using resource calendar method
    def _get_number_of_days(self, date_from, date_to):
        """Returns a float equals to the timedelta between two dates given as string."""

        DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
        from_dt = datetime.datetime.strptime(date_from, DATETIME_FORMAT)
        to_dt = datetime.datetime.strptime(date_to, DATETIME_FORMAT)
        timedelta = to_dt - from_dt
        diff_day = timedelta.days + float(timedelta.seconds) / 86400
        return diff_day

    def unlink(self, cr, uid, ids, context=None):
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.state not in ['draft', 'cancel', 'confirm']:
                raise osv.except_osv(_('Warning!'),_('You cannot delete a leave which is in %s state.')%(rec.state))
        return super(hr_holidays, self).unlink(cr, uid, ids, context)

    def onchange_date_from(self, cr, uid, ids, date_to, date_from):
        """
        If there are no date set for date_to, automatically set one 8 hours later than
        the date_from.
        Also update the number_of_days.
        """
        # date_to has to be greater than date_from
        if (date_from and date_to) and (date_from > date_to):
            raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.'))

        result = {'value': {}}

        # No date_to set so far: automatically compute one 8 hours later
        if date_from and not date_to:
            date_to_with_delta = datetime.datetime.strptime(date_from, tools.DEFAULT_SERVER_DATETIME_FORMAT) + datetime.timedelta(hours=8)
            result['value']['date_to'] = str(date_to_with_delta)

        # Compute and update the number of days
        if (date_to and date_from) and (date_from <= date_to):
            diff_day = self._get_number_of_days(date_from, date_to)
            result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1
        else:
            result['value']['number_of_days_temp'] = 0

        return result

    def onchange_date_to(self, cr, uid, ids, date_to, date_from):
        """
        Update the number_of_days.
        """

        # date_to has to be greater than date_from
        if (date_from and date_to) and (date_from > date_to):
            raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.'))

        result = {'value': {}}

        # Compute and update the number of days
        if (date_to and date_from) and (date_from <= date_to):
            diff_day = self._get_number_of_days(date_from, date_to)
            result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1
        else:
            result['value']['number_of_days_temp'] = 0

        return result

    def add_follower(self, cr, uid, ids, employee_id, context=None):
        employee = self.pool['hr.employee'].browse(cr, uid, employee_id, context=context)
        if employee.user_id:
            self.message_subscribe(cr, uid, ids, [employee.user_id.partner_id.id], context=context)

    def create(self, cr, uid, values, context=None):
        """ Override to avoid automatic logging of creation """
        if context is None:
            context = {}
        employee_id = values.get('employee_id', False)
        context = dict(context, mail_create_nolog=True, mail_create_nosubscribe=True)
        if values.get('state') and values['state'] not in ['draft', 'confirm', 'cancel'] and not self.pool['res.users'].has_group(cr, uid, 'base.group_hr_user'):
            raise osv.except_osv(_('Warning!'), _('You cannot set a leave request as \'%s\'. Contact a human resource manager.') % values.get('state'))
        hr_holiday_id = super(hr_holidays, self).create(cr, uid, values, context=context)
        self.add_follower(cr, uid, [hr_holiday_id], employee_id, context=context)
        return hr_holiday_id

    def write(self, cr, uid, ids, vals, context=None):
        employee_id = vals.get('employee_id', False)
        if vals.get('state') and vals['state'] not in ['draft', 'confirm', 'cancel'] and not self.pool['res.users'].has_group(cr, uid, 'base.group_hr_user'):
            raise osv.except_osv(_('Warning!'), _('You cannot set a leave request as \'%s\'. Contact a human resource manager.') % vals.get('state'))
        hr_holiday_id = super(hr_holidays, self).write(cr, uid, ids, vals, context=context)
        self.add_follower(cr, uid, ids, employee_id, context=context)
        return hr_holiday_id

    def holidays_reset(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {
            'state': 'draft',
            'manager_id': False,
            'manager_id2': False,
        })
        to_unlink = []
        for record in self.browse(cr, uid, ids, context=context):
            for record2 in record.linked_request_ids:
                self.holidays_reset(cr, uid, [record2.id], context=context)
                to_unlink.append(record2.id)
        if to_unlink:
            self.unlink(cr, uid, to_unlink, context=context)
        return True

    def holidays_first_validate(self, cr, uid, ids, context=None):
        obj_emp = self.pool.get('hr.employee')
        ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
        manager = ids2 and ids2[0] or False
        self.holidays_first_validate_notificate(cr, uid, ids, context=context)
        return self.write(cr, uid, ids, {'state':'validate1', 'manager_id': manager})

    def holidays_validate(self, cr, uid, ids, context=None):
        obj_emp = self.pool.get('hr.employee')
        ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
        manager = ids2 and ids2[0] or False
        self.write(cr, uid, ids, {'state':'validate'})
        data_holiday = self.browse(cr, uid, ids)
        for record in data_holiday:
            if record.double_validation:
                self.write(cr, uid, [record.id], {'manager_id2': manager})
            else:
                self.write(cr, uid, [record.id], {'manager_id': manager})
            if record.holiday_type == 'employee' and record.type == 'remove':
                meeting_obj = self.pool.get('calendar.event')
                meeting_vals = {
                    'name': record.name or _('Leave Request'),
                    'categ_ids': record.holiday_status_id.categ_id and [(6,0,[record.holiday_status_id.categ_id.id])] or [],
                    'duration': record.number_of_days_temp * 8,
                    'description': record.notes,
                    'user_id': record.user_id.id,
                    'start': record.date_from,
                    'stop': record.date_to,
                    'allday': False,
                    'state': 'open',            # to block that meeting date in the calendar
                    'class': 'confidential'
                }   
                #Add the partner_id (if exist) as an attendee             
                if record.user_id and record.user_id.partner_id:
                    meeting_vals['partner_ids'] = [(4,record.user_id.partner_id.id)]
                    
                ctx_no_email = dict(context or {}, no_email=True)
                meeting_id = meeting_obj.create(cr, uid, meeting_vals, context=ctx_no_email)
                self._create_resource_leave(cr, uid, [record], context=context)
                self.write(cr, uid, ids, {'meeting_id': meeting_id})
            elif record.holiday_type == 'category':
                emp_ids = obj_emp.search(cr, uid, [('category_ids', 'child_of', [record.category_id.id])])
                leave_ids = []
                batch_context = dict(context, mail_notify_force_send=False)
                for emp in obj_emp.browse(cr, uid, emp_ids, context=context):
                    vals = {
                        'name': record.name,
                        'type': record.type,
                        'holiday_type': 'employee',
                        'holiday_status_id': record.holiday_status_id.id,
                        'date_from': record.date_from,
                        'date_to': record.date_to,
                        'notes': record.notes,
                        'number_of_days_temp': record.number_of_days_temp,
                        'parent_id': record.id,
                        'employee_id': emp.id
                    }
                    leave_ids.append(self.create(cr, uid, vals, context=batch_context))
                for leave_id in leave_ids:
                    # TODO is it necessary to interleave the calls?
                    for sig in ('confirm', 'validate', 'second_validate'):
                        self.signal_workflow(cr, uid, [leave_id], sig)
        return True

    def holidays_confirm(self, cr, uid, ids, context=None):
        for record in self.browse(cr, uid, ids, context=context):
            if record.employee_id and record.employee_id.parent_id and record.employee_id.parent_id.user_id:
                self.message_subscribe_users(cr, uid, [record.id], user_ids=[record.employee_id.parent_id.user_id.id], context=context)
        return self.write(cr, uid, ids, {'state': 'confirm'})

    def holidays_refuse(self, cr, uid, ids, context=None):
        obj_emp = self.pool.get('hr.employee')
        ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
        manager = ids2 and ids2[0] or False
        for holiday in self.browse(cr, uid, ids, context=context):
            if holiday.state == 'validate1':
                self.write(cr, uid, [holiday.id], {'state': 'refuse', 'manager_id': manager})
            else:
                self.write(cr, uid, [holiday.id], {'state': 'refuse', 'manager_id2': manager})
        self.holidays_cancel(cr, uid, ids, context=context)
        return True

    def holidays_cancel(self, cr, uid, ids, context=None):
        for record in self.browse(cr, uid, ids, context=context):
            # Delete the meeting
            if record.meeting_id:
                record.meeting_id.unlink()

            # If a category that created several holidays, cancel all related
            self.signal_workflow(cr, uid, map(attrgetter('id'), record.linked_request_ids or []), 'refuse')

        self._remove_resource_leave(cr, uid, ids, context=context)
        return True

    def check_holidays(self, cr, uid, ids, context=None):
        for record in self.browse(cr, uid, ids, context=context):
            if record.holiday_type != 'employee' or record.type != 'remove' or not record.employee_id or record.holiday_status_id.limit:
                continue
            leave_days = self.pool.get('hr.holidays.status').get_days(cr, uid, [record.holiday_status_id.id], record.employee_id.id, context=context)[record.holiday_status_id.id]
            if float_compare(leave_days['remaining_leaves'], 0, precision_digits=2) == -1 or \
              float_compare(leave_days['virtual_remaining_leaves'], 0, precision_digits=2) == -1:
                # Raising a warning gives a more user-friendly feedback than the default constraint error
                raise Warning(_('The number of remaining leaves is not sufficient for this leave type.\n'
                                'Please verify also the leaves waiting for validation.'))
        return True

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

    def _needaction_domain_get(self, cr, uid, context=None):
        emp_obj = self.pool.get('hr.employee')
        empids = emp_obj.search(cr, uid, [('parent_id.user_id', '=', uid)], context=context)
        dom = ['&', ('state', '=', 'confirm'), ('employee_id', 'in', empids)]
        # if this user is a hr.manager, he should do second validations
        if self.pool.get('res.users').has_group(cr, uid, 'base.group_hr_manager'):
            dom = ['|'] + dom + [('state', '=', 'validate1')]
        return dom

    def holidays_first_validate_notificate(self, cr, uid, ids, context=None):
        for obj in self.browse(cr, uid, ids, context=context):
            self.message_post(cr, uid, [obj.id],
                _("Request approved, waiting second validation."), context=context)
Beispiel #19
0
class desing_laboratory(osv.Model):
    _name = 'desing.laboratory'

    def _get_date_new(self, cr, uid, ids, field, arg, context=None):
        res = {}
        for row in self.browse(cr, uid, ids, context=context):
            if row.state == 'out_time':
                if row.return_date2:
                    self.write(cr, uid, row.id, {'state': 'process'})

        return res

    _columns = {
        'name':
        fields.char("Nombre"),
        'service':
        fields.many2one('services.laboratory', 'Servicio'),
        'app':
        fields.many2one('app.laboratory', 'Aplicación'),
        'company_id':
        fields.many2one('companies.ihce', 'Beneficiario'),
        'id_project':
        fields.many2one('laboratory.ihce', "ID de Proyecto"),
        'date':
        fields.datetime("Fecha de inicio"),
        'date_fin':
        fields.datetime("Fecha de termino"),
        'date_next':
        fields.datetime("Fecha de próxima cita"),
        'percent':
        fields.integer("Porcentaje de avance"),
        'notes':
        fields.text("Observación General"),
        'state':
        fields.selection([
            ('draft', 'Nuevo'),
            ('process', 'Proceso'),
            ('out_time', 'Fuera de tiempo'),
            ('pre_done', 'Para Terminar'),
            ('done', 'Terminado'),
            ('detained', 'Abandonado'),
        ],
                         'Estado',
                         select=True),
        'servicio':
        fields.integer("Servicio"),
        'asesoria':
        fields.integer("Asesoría"),
        'crm_id':
        fields.many2one('crm.project.ihce', "Proyecto crm"),
        'task_id':
        fields.integer("Tarea crm"),
        'user_id':
        fields.many2one(
            'res.users',
            "Responsable",
            help="Es el usuario al que se le contarán los indicadores."),
        'binnacle_lines':
        fields.one2many('binnacle.laboratory', 'service',
                        'Bitácora de trabajo'),
        'cron_id':
        fields.many2one('ir.cron', "Tarea en proceso"),
        'return_date':
        fields.function(_get_date_new, type='boolean',
                        string="Fecha cambiada"),
        'return_date2':
        fields.boolean("Fecha cambiada"),
        'option_service':
        fields.selection([('0', 'Servicio'), ('1', 'Aplicación')], 'Opción'),
        'option':
        fields.selection([('ihce', 'IHCE'), ('emprered', 'Emprered')],
                         'Oficina'),
        'area':
        fields.many2one('responsible.area', "Departamento"),
        'emprered':
        fields.many2one('emprereds', 'Emprered'),
        'sector':
        fields.many2one('sector.actividad.economica',
                        "Sector",
                        help="Sector económico"),
    }

    _defaults = {
        'state':
        'draft',
        'percent':
        0,
        'return_date2':
        False,
        'user_id':
        lambda obj, cr, uid, context: uid,
        'option':
        lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse(
            cr, uid, uid).option,
        'area':
        lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse(
            cr, uid, uid).area.id,
        'emprered':
        lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse(
            cr, uid, uid).emprered.id,
    }

    _order = "date_next asc"

    def create(self, cr, uid, vals, context=None):
        name = ''
        # Generamos id consecutivo, verificamos que el beneficiario no tenga id aún
        row = self.pool.get('companies.ihce').browse(cr,
                                                     uid,
                                                     vals.get('company_id'),
                                                     context=context)
        new_seq = ""
        if not row.id_project_laboratory:
            new_seq = self.pool.get('ir.sequence').get(cr, uid,
                                                       'sector.laboratorio')

            #~ Guardamos el numero de proyecto al beneficiario
            id_project = self.pool.get('laboratory.ihce').create(
                cr, uid, {
                    'name': new_seq,
                    'company_id': vals.get('company_id'),
                    'user_id': vals.get('user_id'),
                    'sector': row.sector.id
                })
            self.pool.get('companies.ihce').write(
                cr, uid, row.id, {'id_project_laboratory': id_project})
            vals.update({'id_project': id_project})
        else:
            vals.update({'id_project': row.id_project_laboratory.id})
            self.pool.get('laboratory.ihce').write(cr, uid,
                                                   vals.get('id_project'),
                                                   {'state': 'process'})

        if vals.get('option_service') == '0':
            servi = self.pool.get('services.laboratory').browse(
                cr, uid, vals.get('service'), context=context)
            name = servi.name
        else:
            if vals.get('option_service') == '1':
                app = self.pool.get('app.laboratory').browse(cr,
                                                             uid,
                                                             vals.get('app'),
                                                             context=context)
                name = app.name

        vals.update({'name': name, 'sector': row.sector.id})

        return super(desing_laboratory, self).create(cr, uid, vals, context)

    def write(self, cr, uid, ids, vals, context=None):
        return super(desing_laboratory, self).write(cr,
                                                    uid,
                                                    ids,
                                                    vals,
                                                    context=context)

    def _check_laboratory(self, cr, uid, ids, context=None):
        row = self.browse(cr, uid, ids[0], context=context)
        fecha_ejecucion = datetime.now()
        if row.date_next:
            fecha_compromiso = datetime.strptime(row.date_next,
                                                 "%Y-%m-%d %H:%M:%S")

            if row.state == 'process':
                if row.date_next:
                    if fecha_compromiso < fecha_ejecucion:
                        self.write(cr,
                                   uid,
                                   ids[0], {
                                       'state': 'out_time',
                                       'return_date2': False
                                   },
                                   context=context)
                        #~ Apartir del momento en que se encuentra fuera de tiempo, tiene 10 días para reagendar o para que se presente el beneficiario, pasado este tiempo el servicio se pondrá en estado detenido.
                        fecha_detenido = fecha_ejecucion + timedelta(days=14)
                        #~ Linea de historial del beneficiario
                        self.pool.get('crm.ihce').create(
                            cr,
                            uid, {
                                'company_id':
                                row.company_id.id,
                                'date':
                                fecha_ejecucion,
                                'name':
                                'El servicio de ' +
                                str(row.service.name.encode('utf-8')) +
                                " del laboratorio de diseño se encuentra fuera de tiempo. No se realizó cita en la fecha establecida.",
                                'user':
                                uid,
                                'date_compromise':
                                fecha_ejecucion,
                                'state':
                                'done'
                            },
                            context=context)

                        #~ self.pool.get('crm.project.ihce').write(cr, uid, [row.crm_id.id], {'state': 'c-out_time'})

                        #~ Enviar correo que el tiempo de la tarea se terminó
                        titulo = "Aviso CRM"
                        texto = "<p>El tiempo para el servicio " + str(
                            row.service.name.encode('utf-8')
                        ) + " del beneficiario " + str(
                            row.company_id.name.encode('utf-8')
                        ) + " con número " + str(
                            row.id_project
                        ) + " está fuera de tiempo. Requerie se agende nueva fecha para cita.</p> "
                        self.pool.get('mail.ihce').send_mail_user(
                            cr,
                            uid,
                            ids,
                            titulo,
                            texto,
                            row.user_id.id,
                            context=context)

            if row.state == 'out_time':
                if fecha_detenido == fecha_ejecucion:
                    self.write(cr,
                               uid,
                               ids[0], {'state': 'detained'},
                               context=context)
                    #~ Linea de historial del beneficiario
                    self.pool.get('crm.ihce').create(
                        cr,
                        uid, {
                            'company_id':
                            row.company_id.id,
                            'date':
                            fecha_ejecucion,
                            'name':
                            'El servicio de ' +
                            str(row.service.name.encode('utf-8')) +
                            " del laboratorio de diseño se encuentra detenido. No se realizó cita en la fecha establecida.",
                            'user':
                            uid,
                            'date_compromise':
                            fecha_ejecucion,
                            'state':
                            'done'
                        },
                        context=context)

                    #~ self.pool.get('crm.project.ihce').write(cr, uid, [row.crm_id.id], {'state': 'e-abandoned'})

                    #~ Enviar correo que el tiempo de la tarea se terminó, el servicio pasa a detenido
                    titulo = "Aviso CRM"
                    texto = "<p>El tiempo para el servicio " + str(
                        row.name.encode('utf-8')
                    ) + " del beneficiario " + row.company_id.name.encode(
                        'utf-8'
                    ) + " con número " + row.id_project + " está fuera de tiempo. El servicio pasa a estado DETENIDO, ya que se le dieron 10 días de plazo después de la última cita.</p> "
                    self.pool.get('mail.ihce').send_mail_user(cr,
                                                              uid,
                                                              ids,
                                                              titulo,
                                                              texto,
                                                              row.user_id.id,
                                                              context=context)

        return True

    def start_process(self, cr, uid, ids, context=None):
        row = self.browse(cr, uid, ids[0], context=context)
        fecha_actual = datetime.now()

        res = {
            'name': 'Process : ' + row.id_project.name,
            'model': 'desing.laboratory',
            'args': repr([ids]),
            'function': '_check_laboratory',
            'priority': 5,
            'interval_number': 1,
            'interval_type': 'hours',
            'user_id': uid,
            'numbercall': -1,
            'doall': False,
            'active': True
        }

        id_cron = self.pool.get('ir.cron').create(cr, uid, res)

        if row.option_service == '0':
            servi = row.service.name.encode('utf-8')
        else:
            servi = row.app.name.encode('utf-8')

        #~ Linea de historial del beneficiario
        self.pool.get('crm.ihce').create(
            cr,
            uid, {
                'company_id': row.company_id.id,
                'date': fecha_actual,
                'name': 'Se ha iniciado el servicio de ' + str(servi) +
                " del laboratorio de diseño.",
                'user': uid,
                'date_compromise': fecha_actual,
                'state': 'done'
            },
            context=context)

        #~ Al aprobarse el registro se crea un proyecto en el crm del usuario.
        valores = {
            'name': servi + " " + str(row.id_project.name),
            'company_id': row.company_id.id,
            'state': 'a-draft',
            'type_crm': 'automatico',
        }
        crm_id = self.pool.get('crm.project.ihce').create(cr,
                                                          uid,
                                                          valores,
                                                          context=context)
        self.pool.get('crm.project.ihce').comenzar(cr,
                                                   uid, [crm_id],
                                                   context=context)

        self.write(cr,
                   uid,
                   ids[0], {
                       'cron_id': id_cron,
                       'state': 'process',
                       'date': fecha_actual,
                       'crm_id': crm_id
                   },
                   context=context)

        #~ self.message_post(cr, uid, [row.id], body=_("Servicio Iniciado"), context=context)

    def onchange_date_next(self, cr, uid, ids, fecha, context=None):
        result = {}
        result['value'] = {}
        fecha_actual = datetime.now()

        if fecha:
            fecha_next = datetime.strptime(fecha, "%Y-%m-%d %H:%M:%S")

            #~ if fecha_next < fecha_actual:
            #~ raise osv.except_osv(_('Advertencia!'), _('La fecha de la próxima cita debe ser posterior al día de hoy!'))
            #~ return False
            #~ else:
            result['value'].update({'date_next': fecha, 'return_date2': True})

            #~ self.message_post(cr, uid, ids, body=_("Cita Reprogramada"), context=context)

        return result

    def detained_process(self, cr, uid, ids, context=None):
        fecha_actual = datetime.now()
        row = self.browse(cr, uid, ids[0], context=context)
        self.write(cr, uid, ids[0], {'state': 'detained'}, context=context)
        self.pool.get('crm.project.ihce').write(cr, uid, [row.crm_id.id],
                                                {'state': 'e-abandoned'})
        #~ Linea de historial del beneficiario
        if row.option_service == '0':
            servi = row.service.name.encode('utf-8')
        else:
            servi = row.app.name.encode('utf-8')
        self.pool.get('crm.ihce').create(
            cr,
            uid, {
                'company_id': row.company_id.id,
                'date': fecha_actual,
                'name': 'El servicio de ' + str(servi) +
                " del laboratorio de diseño ha sido detenido/abandonado.",
                'user': uid,
                'date_compromise': fecha_actual,
                'state': 'done'
            },
            context=context)

        #~ self.message_post(cr, uid, [row.id], body=_("Servicio Detenido"), context=context)

        return True

    def action_detained_wizard(self, cr, uid, ids, context=None):
        """
        Método para crear el wizard y seleccionar el motivo de la cancelación
        """
        # Wizard para cancelar el proyecto
        cancel_project_id = self.pool.get("detained.services").create(
            cr, uid, {'service_id': ids[0]}, context=context)

        res = {
            'name': ("Abandonar Servicio"),
            'view_mode': 'form',
            'view_id': False,
            'view_type': 'form',
            'res_model': 'detained.services',
            'res_id': cancel_project_id,
            'type': 'ir.actions.act_window',
            'nodestroy': True,
            'target': 'new',
            'domain': '[]',
            'context': context,
        }
        return res

    def refresh_process(self, cr, uid, ids, context=None):
        fecha_actual = datetime.now()
        row = self.browse(cr, uid, ids[0], context=context)
        self.write(cr,
                   uid,
                   ids[0], {
                       'state': 'process',
                       'return_date2': False
                   },
                   context=context)
        self.pool.get('crm.project.ihce').write(cr, uid, [row.crm_id.id],
                                                {'state': 'b-progress'})
        #~ Linea de historial del beneficiario
        if row.option_service == '0':
            servi = row.service.name.encode('utf-8')
        else:
            servi = row.app.name.encode('utf-8')
        self.pool.get('crm.ihce').create(
            cr,
            uid, {
                'company_id': row.company_id.id,
                'date': fecha_actual,
                'name': 'El servicio de ' + str(servi) +
                " del laboratorio de diseño ha sido reabierto.",
                'user': uid,
                'date_compromise': fecha_actual,
                'state': 'done'
            },
            context=context)

        #~ self.message_post(cr, uid, [row.id], body=_("Servicio Reabierto"), context=context)

        return True

    def done_process(self, cr, uid, ids, context=None):
        fecha_actual = datetime.now()
        row = self.browse(cr, uid, ids[0], context=context)
        self.write(cr, uid, ids[0], {'state': 'done'}, context=context)
        self.pool.get('crm.project.ihce').write(cr, SUPERUSER_ID,
                                                [row.crm_id.id],
                                                {'state': 'd-done'})
        #~ Linea de historial del beneficiario
        if row.option_service == '0':
            servi = row.service.name.encode('utf-8')
        else:
            servi = row.app.name.encode('utf-8')

        self.pool.get('crm.ihce').create(
            cr,
            uid, {
                'company_id': row.company_id.id,
                'date': fecha_actual,
                'name': 'El servicio de ' + str(servi) +
                " del laboratorio de diseño ha sido concluido.",
                'user': uid,
                'date_compromise': fecha_actual,
                'state': 'done'
            },
            context=context)

        #~ self.message_post(cr, uid, [row.id], body=_("Servicio Terminado"), context=context)

        return True

    def onchange_company(self,
                         cr,
                         uid,
                         ids,
                         company,
                         user,
                         service,
                         app,
                         context=None):
        result = {}
        result['value'] = {}

        if user:
            us = self.pool.get('res.users').browse(cr, uid, user)
        if company:
            if service:
                services_ids = self.search(cr, uid,
                                           [('company_id', '=', company),
                                            ('service', '=', service)])
                if services_ids:
                    raise osv.except_osv(
                        _('Advertencia!'),
                        _('Ya existe un servicio para la empresa seleccionada, que ha creado el usuario '
                          + str(us.name.encode('utf-8')) +
                          '. Por favor verifique si es necesario crear otro!'))
            if app:
                app_ids = self.search(cr, uid, [('company_id', '=', company),
                                                ('app', '=', app)])
                if app_ids:
                    raise osv.except_osv(
                        _('Advertencia!'),
                        _('Ya existe una aplicación para la empresa seleccionada, que ha creado el usuario '
                          + str(us.name.encode('utf-8')) +
                          '.  Por favor verifique si es necesario crear otra!')
                    )

        return result

    def unlink(self, cr, uid, ids, context=None):
        data = self.read(cr, uid, ids, ['state'], context=context)
        unlink_ids = []
        for row in data:
            if row['state'] in ['draft']:
                unlink_ids.append(row['id'])
            else:
                raise osv.except_osv(
                    _('Acción Invalida!'),
                    _('No puede eliminar el servicio/aplicación.!'))

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

    def onchange_user(self, cr, uid, ids, user_id, context=None):
        result = {}
        result['value'] = {}

        if user_id:
            row = self.pool.get('res.users').browse(cr, uid, user_id)

            result['value'].update({
                'option': row.option,
                'area': row.area.id,
                'emprered': row.emprered.id
            })

        return result
class user_story_phase(osv.Model):
    _name = "user.story.phase"
    _description = "User Story Phase"

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

        data_phase = self.browse(cr, uid, ids[0], context=context)
        prev_ids = data_phase.previous_phase_ids
        next_ids = data_phase.next_phase_ids
        # it should neither be in prev_ids nor in next_ids
        if (data_phase in prev_ids) or (data_phase in next_ids):
            return False
        ids = [id for id in prev_ids if id in next_ids]
        # both prev_ids and next_ids must be unique
        if ids:
            return False
        # unrelated user_story
        prev_ids = [rec.id for rec in prev_ids]
        next_ids = [rec.id for rec in next_ids]
        # iter prev_ids
        while prev_ids:
            cr.execute(
                'SELECT distinct prv_phase_id FROM user_story_phase_rel WHERE next_phase_id IN %s',
                (tuple(prev_ids), ))
            prv_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
            if data_phase.id in prv_phase_ids:
                return False
            ids = [id for id in prv_phase_ids if id in next_ids]
            if ids:
                return False
            prev_ids = prv_phase_ids
        # iter next_ids
        while next_ids:
            cr.execute(
                'SELECT distinct next_phase_id FROM user_story_phase_rel WHERE prv_phase_id IN %s',
                (tuple(next_ids), ))
            next_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
            if data_phase.id in next_phase_ids:
                return False
            ids = [id for id in next_phase_ids if id in prev_ids]
            if ids:
                return False
            next_ids = next_phase_ids
        return True

    def _check_dates(self, cr, uid, ids, context=None):
        for phase in self.read(cr,
                               uid,
                               ids, ['date_start', 'date_end'],
                               context=context):
            if phase['date_start'] and phase[
                    'date_end'] and phase['date_start'] > phase['date_end']:
                return False
        return True
#
#    def _compute_progress(self, cr, uid, ids, field_name, arg, context=None):
#        res = {}
#        if not ids:
#            return res
#        for phase in self.browse(cr, uid, ids, context=context):
#            if phase.state=='done':
#                res[phase.id] = 100.0
#                continue
#            elif phase.state=="cancelled":
#                res[phase.id] = 0.0
#                continue
#            elif not phase.task_ids:
#                res[phase.id] = 0.0
#                continue
#
#            tot = done = 0.0
#            for task in phase.task_ids:
#                tot += task.total_hours
#                done += min(task.effective_hours, task.total_hours)
#
#            if not tot:
#                res[phase.id] = 0.0
#            else:
#                res[phase.id] = round(100.0 * done / tot, 2)
#        return res

    _columns = {
        'name':
        fields.char("Name", size=64, required=True),
        'user_story_id':
        fields.many2one('user.story', 'User Story', required=True,
                        select=True),
        'state':
        fields.selection(
            [('draft', 'New'), ('cancelled', 'Cancelled'),
             ('open', 'In Progress'), ('pending', 'Pending'),
             ('done', 'Done')],
            'Status',
            readonly=True,
            required=True,
            help=
            'If the phase is created the status \'Draft\'.\n If the phase is started, the status becomes \'In Progress\'.\n If review is needed the phase is in \'Pending\' status.\
                                  \n If the phase is over, the status is set to \'Done\'.'
        ),
        'date_start':
        fields.datetime(
            'Start Date',
            select=True,
            help=
            "It's computed by the scheduler according the project date or the end date of the previous phase.",
            states={
                'done': [('readonly', True)],
                'cancelled': [('readonly', True)]
            }),
        'date_end':
        fields.datetime(
            'End Date',
            help=
            " It's computed by the scheduler according to the start date and the duration.",
            states={
                'done': [('readonly', True)],
                'cancelled': [('readonly', True)]
            }),
        'sequence':
        fields.integer(
            'Sequence',
            select=True,
            help="Gives the sequence order when displaying a list of phases."),
        'duration':
        fields.float('Duration',
                     required=True,
                     help="By default in days",
                     states={
                         'done': [('readonly', True)],
                         'cancelled': [('readonly', True)]
                     }),
        'next_phase_ids':
        fields.many2many('user.story.phase',
                         'user_story_phase_rel',
                         'prv_phase_id',
                         'next_phase_id',
                         'Next Phases',
                         states={'cancelled': [('readonly', True)]}),
        'previous_phase_ids':
        fields.many2many('user.story.phase',
                         'user_story_phase_rel',
                         'next_phase_id',
                         'prv_phase_id',
                         'Previous Phases',
                         states={'cancelled': [('readonly', True)]}),
        'product_uom':
        fields.many2one(
            'product.uom',
            'Duration Unit of Measure',
            required=True,
            help=
            "Unit of Measure (Unit of Measure) is the unit of measurement for Duration",
            states={
                'done': [('readonly', True)],
                'cancelled': [('readonly', True)]
            }),
        'constraint_date_start':
        fields.datetime('Minimum Start Date',
                        help='force the phase to start after this date',
                        states={
                            'done': [('readonly', True)],
                            'cancelled': [('readonly', True)]
                        }),
        'constraint_date_end':
        fields.datetime('Deadline',
                        help='force the phase to finish before this date',
                        states={
                            'done': [('readonly', True)],
                            'cancelled': [('readonly', True)]
                        }),
        'user_force_ids':
        fields.many2many('res.users', string='Force Assigned Users'),
        'user_ids':
        fields.one2many(
            'user.story.user.allocation',
            'phase_id',
            "Assigned Users",
            states={
                'done': [('readonly', True)
                         ],
                'cancelled': [('readonly', True)]
            },
            help=
            "The resources on the project can be computed automatically by the scheduler."
        ),
    }

    #        'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
    #        'progress': fields.function(_compute_progress, string='Progress', help="Computed based on related tasks"),

    _defaults = {
        'state': 'draft',
        'sequence': 10,
    }
    _order = "user_story_id, date_start, sequence"
    _constraints = [
        (_check_recursion, 'Loops in phases not allowed',
         ['next_phase_ids', 'previous_phase_ids']),
        (_check_dates, 'Phase start-date must be lower than phase end-date.',
         ['date_start', 'date_end']),
    ]

    def onchange_user_story(self, cr, uid, ids, user_story, context=None):
        return {}

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None:
            default = {}
        if not default.get('name', False):
            default.update(name=_('%s (copy)') %
                           (self.browse(cr, uid, id, context=context).name))
        return super(user_story_phase, self).copy(cr, uid, id, default,
                                                  context)

    def set_draft(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state': 'draft'})
        return True

    def set_open(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state': 'open'})
        return True

    def set_pending(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state': 'pending'})
        return True

    def set_cancel(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state': 'cancelled'})
        return True

    def set_done(self, cr, uid, ids, *args):
        self.write(cr, uid, ids, {'state': 'done'})
        return True
Beispiel #21
0
class binnacle_laboratory(osv.Model):
    _name = 'binnacle.laboratory'

    _columns = {
        'name':
        fields.char("Actividad", size=200),
        'id_project':
        fields.many2one('laboratory.ihce', "ID de Proyecto"),
        'service':
        fields.many2one('desing.laboratory', 'Servicio'),
        'date':
        fields.datetime("Fecha"),
        'date_next':
        fields.datetime("Próxima cita"),
        'notes':
        fields.text("Comentarios/Acuerdos"),
        'user_id':
        fields.many2one(
            'res.users',
            "Responsable",
            help="Es el usuario al que se le contarán los indicadores."),
        'percent':
        fields.integer("Porcentaje de avance"),
        'state':
        fields.selection([
            ('draft', 'Nuevo'),
            ('done', 'Terminado'),
        ], 'Estado'),
    }

    _defaults = {
        'user_id': lambda obj, cr, uid, context: uid,
        'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
        'state': 'draft',
    }

    def create(self, cr, uid, vals, context=None):
        fecha_actual = datetime.now()
        row = self.pool.get('desing.laboratory').browse(
            cr, uid, vals.get('service'))
        vals.update({'id_project': row.id_project.id})
        if vals.get('percent') >= 0 and vals.get('percent') <= 100:
            #~ Creamos la tarea en el crm

            notas = vals.get('notes')
            if notas:
                notas = notas.encode('utf-8')
            else:
                notas = ""

            if vals.get('percent') == 100:
                if row.task_id != 0:
                    self.pool.get('crm.task').terminar(cr,
                                                       SUPERUSER_ID,
                                                       [row.task_id],
                                                       context=context)

                self.pool.get('desing.laboratory').write(
                    cr, uid, vals.get('service'), {
                        'percent': vals.get('percent'),
                        'date_next': False,
                        'state': 'pre_done',
                        'date_fin': fecha_actual
                    })
            else:
                if row.task_id != 0:
                    self.pool.get('crm.task').terminar(cr,
                                                       SUPERUSER_ID,
                                                       [row.task_id],
                                                       context=context)

                datos = {
                    'name': vals.get('name').encode('utf-8'),
                    'date_compromise': vals.get('date_next'),
                    'user_id': uid,
                    'crm_id': row.crm_id.id,
                    'notes': notas,
                    'type_task': 'automatico',
                }
                task_id = self.pool.get('crm.task').create(cr,
                                                           SUPERUSER_ID,
                                                           datos,
                                                           context=context)

                self.pool.get('desing.laboratory').write(
                    cr, uid, vals.get('service'), {
                        'percent': vals.get('percent'),
                        'date_next': vals.get('date_next'),
                        'task_id': task_id,
                        'state': 'process'
                    })

            vals.update({'state': 'done'})

            #~ Linea de historial del beneficiario
            self.pool.get('crm.ihce').create(
                cr,
                uid, {
                    'company_id':
                    row.company_id.id,
                    'date':
                    fecha_actual,
                    'name':
                    str(vals.get('name').encode('utf-8')) +
                    " para el servicio de " + str(row.name.encode('utf-8')) +
                    " del laboratorio de diseño. " + notas,
                    'user':
                    uid,
                    'date_compromise':
                    fecha_actual,
                    'state':
                    'done'
                },
                context=context)

        else:
            raise osv.except_osv(
                _('Advertencia!'),
                _('El porcentaje ingresado no se encuentra dentro del rango correcto.!'
                  ))
            return False

        return super(binnacle_laboratory, self).create(cr, uid, vals, context)
Beispiel #22
0
class payment_line(osv.osv):
    _name = 'payment.line'
    _description = 'Payment Line'

    def translate(self, orig):
        return {
            "due_date": "date_maturity",
            "reference": "ref"
        }.get(orig, orig)

    def _info_owner(self, cr, uid, ids, name=None, args=None, context=None):
        result = {}
        for line in self.browse(cr, uid, ids, context=context):
            owner = line.order_id.mode.bank_id.partner_id
            result[line.id] = self._get_info_partner(cr,
                                                     uid,
                                                     owner,
                                                     context=context)
        return result

    def _get_info_partner(self, cr, uid, partner_record, context=None):
        if not partner_record:
            return False
        st = partner_record.street or ''
        st1 = partner_record.street2 or ''
        zip = partner_record.zip or ''
        city = partner_record.city or ''
        zip_city = zip + ' ' + city
        cntry = partner_record.country_id and partner_record.country_id.name or ''
        return partner_record.name + "\n" + st + " " + st1 + "\n" + zip_city + "\n" + cntry

    def _info_partner(self, cr, uid, ids, name=None, args=None, context=None):
        result = {}
        for line in self.browse(cr, uid, ids, context=context):
            result[line.id] = False
            if not line.partner_id:
                break
            result[line.id] = self._get_info_partner(cr,
                                                     uid,
                                                     line.partner_id,
                                                     context=context)
        return result

    #dead code
    def select_by_name(self, cr, uid, ids, name, args, context=None):
        if not ids: return {}
        partner_obj = self.pool.get('res.partner')

        cr.execute(
            """SELECT pl.id, ml.%s
            FROM account_move_line ml
                INNER JOIN payment_line pl
                ON (ml.id = pl.move_line_id)
                WHERE pl.id IN %%s""" % self.translate(name), (tuple(ids), ))
        res = dict(cr.fetchall())

        if name == 'partner_id':
            partner_name = {}
            for p_id, p_name in partner_obj.name_get(
                    cr,
                    uid,
                    filter(lambda x: x and x != 0, res.values()),
                    context=context):
                partner_name[p_id] = p_name

            for id in ids:
                if id in res and partner_name:
                    res[id] = (res[id], partner_name[res[id]])
                else:
                    res[id] = (False, False)
        else:
            for id in ids:
                res.setdefault(id, (False, ""))
        return res

    def _amount(self, cursor, user, ids, name, args, context=None):
        if not ids:
            return {}
        currency_obj = self.pool.get('res.currency')
        if context is None:
            context = {}
        res = {}

        for line in self.browse(cursor, user, ids, context=context):
            ctx = context.copy()
            ctx['date'] = line.order_id.date_done or time.strftime('%Y-%m-%d')
            res[line.id] = currency_obj.compute(cursor,
                                                user,
                                                line.currency.id,
                                                line.company_currency.id,
                                                line.amount_currency,
                                                context=ctx)
        return res

    def _get_currency(self, cr, uid, context=None):
        user_obj = self.pool.get('res.users')
        currency_obj = self.pool.get('res.currency')
        user = user_obj.browse(cr, uid, uid, context=context)

        if user.company_id:
            return user.company_id.currency_id.id
        else:
            return currency_obj.search(cr, uid, [('rate', '=', 1.0)])[0]

    def _get_date(self, cr, uid, context=None):
        if context is None:
            context = {}
        payment_order_obj = self.pool.get('payment.order')
        date = False

        if context.get('order_id') and context['order_id']:
            order = payment_order_obj.browse(cr,
                                             uid,
                                             context['order_id'],
                                             context=context)
            if order.date_prefered == 'fixed':
                date = order.date_scheduled
            else:
                date = time.strftime('%Y-%m-%d')
        return date

    def _get_ml_inv_ref(self, cr, uid, ids, *a):
        res = {}
        for id in self.browse(cr, uid, ids):
            res[id.id] = False
            if id.move_line_id:
                if id.move_line_id.invoice:
                    res[id.id] = id.move_line_id.invoice.id
        return res

    def _get_ml_maturity_date(self, cr, uid, ids, *a):
        res = {}
        for id in self.browse(cr, uid, ids):
            if id.move_line_id:
                res[id.id] = id.move_line_id.date_maturity
            else:
                res[id.id] = False
        return res

    def _get_ml_created_date(self, cr, uid, ids, *a):
        res = {}
        for id in self.browse(cr, uid, ids):
            if id.move_line_id:
                res[id.id] = id.move_line_id.date_created
            else:
                res[id.id] = False
        return res

    _columns = {
        'name':
        fields.char('Your Reference', required=True),
        'communication':
        fields.char(
            'Communication',
            required=True,
            help=
            "Used as the message between ordering customer and current company. Depicts 'What do you want to say to the recipient about this order ?'"
        ),
        'communication2':
        fields.char('Communication 2',
                    help='The successor message of Communication.'),
        'move_line_id':
        fields.many2one(
            'account.move.line',
            'Entry line',
            domain=[('reconcile_id', '=', False),
                    ('account_id.type', '=', 'payable')],
            select=True,
            help=
            'This Entry Line will be referred for the information of the ordering customer.'
        ),
        'amount_currency':
        fields.float('Amount in Partner Currency',
                     digits=(16, 2),
                     required=True,
                     help='Payment amount in the partner currency'),
        'currency':
        fields.many2one('res.currency', 'Partner Currency', required=True),
        'company_currency':
        fields.many2one('res.currency', 'Company Currency', readonly=True),
        'bank_id':
        fields.many2one('res.partner.bank', 'Destination Bank Account'),
        'order_id':
        fields.many2one('payment.order',
                        'Order',
                        required=True,
                        ondelete='cascade',
                        select=True),
        'partner_id':
        fields.many2one('res.partner',
                        string="Partner",
                        required=True,
                        help='The Ordering Customer'),
        'amount':
        fields.function(_amount,
                        string='Amount in Company Currency',
                        type='float',
                        help='Payment amount in the company currency'),
        'ml_date_created':
        fields.function(_get_ml_created_date,
                        string="Effective Date",
                        type='date',
                        help="Invoice Effective Date"),
        'ml_maturity_date':
        fields.function(_get_ml_maturity_date, type='date', string='Due Date'),
        'ml_inv_ref':
        fields.function(_get_ml_inv_ref,
                        type='many2one',
                        relation='account.invoice',
                        string='Invoice Ref.'),
        'info_owner':
        fields.function(_info_owner,
                        string="Owner Account",
                        type="text",
                        help='Address of the Main Partner'),
        'info_partner':
        fields.function(_info_partner,
                        string="Destination Account",
                        type="text",
                        help='Address of the Ordering Customer.'),
        'date':
        fields.date(
            'Payment Date',
            help=
            "If no payment date is specified, the bank will treat this payment line directly"
        ),
        'create_date':
        fields.datetime('Created', readonly=True),
        'state':
        fields.selection([('normal', 'Free'), ('structured', 'Structured')],
                         'Communication Type',
                         required=True),
        'bank_statement_line_id':
        fields.many2one('account.bank.statement.line', 'Bank statement line'),
        'company_id':
        fields.related('order_id',
                       'company_id',
                       type='many2one',
                       relation='res.company',
                       string='Company',
                       store=True,
                       readonly=True),
    }
    _defaults = {
        'name':
        lambda obj, cursor, user, context: obj.pool.get('ir.sequence').get(
            cursor, user, 'payment.line'),
        'state':
        'normal',
        'currency':
        _get_currency,
        'company_currency':
        _get_currency,
        'date':
        _get_date,
    }
    _sql_constraints = [
        ('name_uniq', 'UNIQUE(name, company_id)',
         'The payment line name must be unique per company!'),
    ]

    def onchange_move_line(self,
                           cr,
                           uid,
                           ids,
                           move_line_id,
                           payment_type,
                           date_prefered,
                           date_scheduled,
                           currency=False,
                           company_currency=False,
                           context=None):
        data = {}
        move_line_obj = self.pool.get('account.move.line')

        data['amount_currency'] = data['communication'] = data[
            'partner_id'] = data['bank_id'] = data['amount'] = False

        if move_line_id:
            line = move_line_obj.browse(cr, uid, move_line_id, context=context)
            data['amount_currency'] = line.amount_residual_currency

            res = self.onchange_amount(cr, uid, ids, data['amount_currency'],
                                       currency, company_currency, context)
            if res:
                data['amount'] = res['value']['amount']
            data['partner_id'] = line.partner_id.id
            temp = line.currency_id and line.currency_id.id or False
            if not temp:
                if line.invoice:
                    data['currency'] = line.invoice.currency_id.id
            else:
                data['currency'] = temp

            # calling onchange of partner and updating data dictionary
            temp_dict = self.onchange_partner(cr, uid, ids, line.partner_id.id,
                                              payment_type)
            data.update(temp_dict['value'])

            data['communication'] = line.ref

            if date_prefered == 'now':
                #no payment date => immediate payment
                data['date'] = False
            elif date_prefered == 'due':
                data['date'] = line.date_maturity
            elif date_prefered == 'fixed':
                data['date'] = date_scheduled
        return {'value': data}

    def onchange_amount(self,
                        cr,
                        uid,
                        ids,
                        amount,
                        currency,
                        cmpny_currency,
                        context=None):
        if (not amount) or (not cmpny_currency):
            return {'value': {'amount': False}}
        res = {}
        currency_obj = self.pool.get('res.currency')
        company_amount = currency_obj.compute(cr, uid, currency,
                                              cmpny_currency, amount)
        res['amount'] = company_amount
        return {'value': res}

    def onchange_partner(self,
                         cr,
                         uid,
                         ids,
                         partner_id,
                         payment_type,
                         context=None):
        data = {}
        partner_obj = self.pool.get('res.partner')
        payment_mode_obj = self.pool.get('payment.mode')
        data['info_partner'] = data['bank_id'] = False

        if partner_id:
            part_obj = partner_obj.browse(cr, uid, partner_id, context=context)
            partner = part_obj.name or ''
            data['info_partner'] = self._get_info_partner(cr,
                                                          uid,
                                                          part_obj,
                                                          context=context)

            if part_obj.bank_ids and payment_type:
                bank_type = payment_mode_obj.suitable_bank_types(
                    cr, uid, payment_type, context=context)
                for bank in part_obj.bank_ids:
                    if bank.state in bank_type:
                        data['bank_id'] = bank.id
                        break
        return {'value': data}

    def fields_get(self,
                   cr,
                   uid,
                   fields=None,
                   context=None,
                   write_access=True,
                   attributes=None):
        res = super(payment_line, self).fields_get(cr, uid, fields, context,
                                                   write_access, attributes)
        if 'communication2' in res:
            res['communication2'].setdefault('states', {})
            res['communication2']['states']['structured'] = [('readonly', True)
                                                             ]
            res['communication2']['states']['normal'] = [('readonly', False)]
        return res
Beispiel #23
0
class wizard(osv.TransientModel):
    """
        A wizard to manage the modification of protocol object
    """
    _name = 'protocollo.fascicola.wizard'
    _description = 'Fascicola Protocollo'

    def set_before(self, before, label, value):
        if not value:
            value = ''
        before += value + '\n'
        return before

    def set_after(self, after, label, value):
        after += value + '\n'
        return after

    _columns = {
        'complete_name':
        fields.char('Numero Protocollo',
                    size=256,
                    required=True,
                    readonly=True),
        'registration_date':
        fields.datetime('Data Registrazione', readonly=True),
        'type':
        fields.selection([('out', 'Uscita'), ('in', 'Ingresso'),
                          ('internal', 'Interno')],
                         'Tipo',
                         size=32,
                         required=True,
                         readonly=True),
        'cause':
        fields.text('Motivo della Modifica', required=True),
        'dossier_ids':
        fields.many2many('protocollo.dossier',
                         'protocollo_fascicola_wizard_dossier_rel',
                         'wizard_id', 'dossier_id', 'Fascicoli'),
    }

    def _default_complete_name(self, cr, uid, context):
        protocollo = self.pool.get('protocollo.protocollo').browse(
            cr, uid, context['active_id'])
        return protocollo.complete_name

    def _default_registration_date(self, cr, uid, context):
        protocollo = self.pool.get('protocollo.protocollo').browse(
            cr, uid, context['active_id'])
        return protocollo.registration_date

    def _default_type(self, cr, uid, context):
        protocollo = self.pool.get('protocollo.protocollo').browse(
            cr, uid, context['active_id'])
        return protocollo.type

    def _default_dossier_ids(self, cr, uid, context):
        protocollo = self.pool.get('protocollo.protocollo').browse(
            cr, uid, context['active_id'])
        dossier_ids = []
        for dossier_id in protocollo.dossier_ids:
            dossier_ids.append(dossier_id.id)
        return [(6, 0, dossier_ids)]

    _defaults = {
        'complete_name': _default_complete_name,
        'registration_date': _default_registration_date,
        'type': _default_type,
        'dossier_ids': _default_dossier_ids,
    }

    def action_save(self, cr, uid, ids, context=None):
        vals = {}
        before = {}
        after = {}
        wizard = self.browse(cr, uid, ids[0], context)
        protocollo_obj = self.pool.get('protocollo.protocollo')
        protocollo = protocollo_obj.browse(cr,
                                           uid,
                                           context['active_id'],
                                           context=context)
        before['Fascicolo'] = ""
        after['Fascicolo'] = ""
        vals['dossier_ids'] = [[6, 0, [d.id for d in wizard.dossier_ids]]]
        before['Fascicolo'] = self.set_before(
            before['Fascicolo'], 'Fascicolo',
            ', '.join([d.name for d in protocollo.dossier_ids]))
        after['Fascicolo'] = self.set_after(
            after['Fascicolo'], 'Fascicolo',
            ', '.join([dw.name for dw in wizard.dossier_ids]))

        protocollo_obj.write(cr, uid, [context['active_id']], vals)

        action_class = "history_icon update"
        body = "<div class='%s'><ul>" % action_class
        for key, before_item in before.items():
            if before[key] != after[key]:
                body = body + "<li>%s: <span style='color:#990000'> %s</span> -> <span style='color:#009900'> %s </span></li>" \
                                % (str(key), before_item.encode("utf-8"), after[key].encode("utf-8"))
            else:
                body = body + "<li>%s: <span style='color:#999'> %s</span> -> <span style='color:#999'> %s </span></li>" \
                              % (str(key), before_item.encode("utf-8"), after[key].encode("utf-8"))

        post_vars = {
            'subject': "Modifica Fascicolazione: \'%s\'" % wizard.cause,
            'body': body,
            'model': "protocollo.protocollo",
            'res_id': context['active_id'],
        }
        body += "</ul></div>"

        new_context = dict(context).copy()
        # if protocollo.typology.name == 'PEC':
        new_context.update({'pec_messages': True})

        thread_pool = self.pool.get('protocollo.protocollo')
        thread_pool.message_post(cr,
                                 uid,
                                 context['active_id'],
                                 type="notification",
                                 context=new_context,
                                 **post_vars)

        return {'type': 'ir.actions.act_window_close'}
Beispiel #24
0
class survey(osv.osv):
    _name = 'survey'
    _description = 'Survey'
    _rec_name = 'title'

    def default_get(self, cr, uid, fields, context=None):
        data = super(survey, self).default_get(cr, uid, fields, context)
        return data

    _columns = {
        'id':
        fields.integer('ID'),
        'title':
        fields.char('Survey Title', size=128, required=1),
        'page_ids':
        fields.one2many('survey.page', 'survey_id', 'Page'),
        'date_open':
        fields.datetime('Survey Open Date', readonly=1),
        'date_close':
        fields.datetime('Survey Close Date', readonly=1),
        'max_response_limit':
        fields.integer('Maximum Answer Limit',
                       help="Set to one if survey is answerable only once"),
        'response_user':
        fields.integer(
            'Maximum Answer per User',
            help="Set to one if  you require only one Answer per user"),
        'state':
        fields.selection([('open', 'Open'), ('cancel', 'Cancelled'),
                          ('close', 'Closed')],
                         'Status',
                         readonly=True),
        'responsible_id':
        fields.many2one('res.users',
                        'Responsible',
                        help="User responsible for survey"),
        'tot_start_survey':
        fields.integer("Total Started Survey", readonly=1),
        'tot_comp_survey':
        fields.integer("Total Completed Survey", readonly=1),
        'note':
        fields.text('Description', size=128),
        'history':
        fields.one2many('survey.history',
                        'survey_id',
                        'History Lines',
                        readonly=True),
        'users':
        fields.many2many('res.users', 'survey_users_rel', 'sid', 'uid',
                         'Users'),
        'send_response':
        fields.boolean('Email Notification on Answer'),
        'type':
        fields.many2one('survey.type', 'Type'),
        'color':
        fields.integer('Color Index'),
        'invited_user_ids':
        fields.many2many('res.users', 'survey_invited_user_rel', 'sid', 'uid',
                         'Invited User'),
    }
    _defaults = {
        'state': lambda *a: "open",
        'tot_start_survey': lambda *a: 0,
        'tot_comp_survey': lambda *a: 0,
        'send_response': lambda *a: 1,
        'response_user': lambda *a: 1,
        'date_open': fields.datetime.now,
    }

    def survey_open(self, cr, uid, ids, arg):
        self.write(cr, uid, ids, {
            'state': 'open',
            'date_open': strftime("%Y-%m-%d %H:%M:%S")
        })
        return True

    def survey_close(self, cr, uid, ids, arg):
        self.write(cr, uid, ids, {
            'state': 'close',
            'date_close': strftime("%Y-%m-%d %H:%M:%S")
        })
        return True

    def survey_cancel(self, cr, uid, ids, arg):
        self.write(cr, uid, ids, {'state': 'cancel'})
        return True

    def copy(self, cr, uid, ids, default=None, context=None):
        vals = {}
        current_rec = self.read(cr, uid, ids, context=context)
        title = _("%s (copy)") % (current_rec.get('title'))
        vals.update({'title': title})
        vals.update({
            'history': [],
            'tot_start_survey': 0,
            'tot_comp_survey': 0
        })
        return super(survey, self).copy(cr, uid, ids, vals, 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).
        @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 Survey IDs
        @param context: A standard dictionary for contextual values
        @return : Dictionary value for print survey form.
        """
        if context is None:
            context = {}
        datas = {}
        if 'response_id' in context:
            response_id = context.get('response_id', 0)
            datas['ids'] = [context.get('survey_id', 0)]
        else:
            response_id = self.pool.get('survey.response').search(
                cr, uid, [('survey_id', '=', ids)], context=context)
            datas['ids'] = ids
        page_setting = {
            'orientation': 'vertical',
            'without_pagebreak': 0,
            'paper_size': 'letter',
            'page_number': 1,
            'survey_title': 1
        }
        report = {}
        if response_id and response_id[0]:
            context.update({'survey_id': datas['ids']})
            datas['form'] = page_setting
            datas['model'] = 'survey.print.answer'
            report = {
                'type': 'ir.actions.report.xml',
                'report_name': 'survey.browse.response',
                'datas': datas,
                'context': context,
                'nodestroy': True,
            }
        else:

            datas['form'] = page_setting
            datas['model'] = 'survey.print'
            report = {
                'type': 'ir.actions.report.xml',
                'report_name': 'survey.form',
                'datas': datas,
                'context': context,
                'nodestroy': True,
            }
        return report

    def fill_survey(self, cr, uid, ids, context=None):
        sur_obj = self.read(cr,
                            uid,
                            ids, ['title', 'page_ids'],
                            context=context)
        for sur in sur_obj:
            name = sur['title']
            pages = sur['page_ids']
            if not pages:
                raise osv.except_osv(
                    _('Warning!'),
                    _('This survey has no question defined. Please define the questions and answers first.'
                      ))
            context.update({'active': False, 'survey_id': ids[0]})
        return {
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'survey.question.wiz',
            'type': 'ir.actions.act_window',
            'target': 'new',
            'name': name,
            'context': context
        }

    def test_survey(self, cr, uid, ids, context=None):
        sur_obj = self.read(cr,
                            uid,
                            ids, ['title', 'page_ids'],
                            context=context)
        for sur in sur_obj:
            name = sur['title']
            pages = sur['page_ids']
            if not pages:
                raise osv.except_osv(
                    _('Warning!'),
                    _('This survey has no pages defined. Please define pages first.'
                      ))
            context.update({'active': False, 'survey_id': ids[0]})
        return {
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'survey.question.wiz',
            'type': 'ir.actions.act_window',
            'target': 'new',
            'name': name,
            'context': context
        }

    def edit_survey(self, cr, uid, ids, context=None):
        sur_obj = self.read(cr,
                            uid,
                            ids, ['title', 'page_ids'],
                            context=context)
        for sur in sur_obj:
            name = sur['title']
            pages = sur['page_ids']
            if not pages:
                raise osv.except_osv(
                    _('Warning!'),
                    _('This survey has no question defined. Please define the questions and answers first.'
                      ))
            context.update({'survey_id': ids[0]})
        return {
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'survey.question.wiz',
            'type': 'ir.actions.act_window',
            'target': 'new',
            'name': name,
            'context': context
        }
class kg_partner(osv.osv):

	_name = "res.partner"
	_inherit = "res.partner"
	_description = "Partner Managment"
	
	def _get_modify(self, cr, uid, ids, field_name, arg,  context=None):
		res={}
		if field_name == 'modify':
			for h in self.browse(cr, uid, ids, context=None):	
				res[h.id] = 'no'
				cr.execute(""" select * from
				(SELECT tc.table_schema, tc.constraint_name, tc.table_name, kcu.column_name, ccu.table_name
				AS foreign_table_name, ccu.column_name AS foreign_column_name
				FROM information_schema.table_constraints tc
				JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
				JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name
				WHERE constraint_type = 'FOREIGN KEY'
				AND ccu.table_name='%s')
				as sam  """ %('res_partner'))
				data = cr.dictfetchall()	
				if data:
					for var in data:
						data = var
						chk_sql = 'Select COALESCE(count(*),0) as cnt from '+str(data['table_name'])+' where '+data['column_name']+' = '+str(ids[0])
						cr.execute(chk_sql)			
						out_data = cr.dictfetchone()
						if out_data:
							if out_data['cnt'] > 0:
								res[h.id] = 'yes'
		return res
		
	_columns = {
	
	'city_id' : fields.many2one('res.city', 'City'),
	'tin_no' : fields.char('TIN'),
	'vat_no' : fields.char('VAT'),
	'pan_no' : fields.char('PAN'),
	'tan_no' : fields.char('TAN'),
	'cst_no' : fields.char('CST'),
	'gst_no' : fields.char('GST'),
	'supply_type': fields.selection([('material','Material'),('service','Service'),('contractor','Contractor'),('labour','Labour'),('all','All')],'Supply Type'),
	'company_type': fields.selection([('individual','Individual'),('company','Company'),('trust','Trust')],'Type'),
	'tds': fields.selection([('yes','Yes'),('no','No')],'TDS Applicable'),
	'grade': fields.selection([('a','A'),('b','B'),('c','C')],'Grade'),
	'payment_id': fields.many2one('kg.payment.master','Payment Terms'),
	'language': fields.selection([('tamil', 'Tamil'),('english', 'English'),('hindi', 'Hindi'),('malayalam', 'Malayalam'),('others','Others')],'Preferred Language'),
	'cheque_in_favour': fields.char('Cheque in Favor Of'),
	'advance_limit': fields.float('Credit Limit'),
	'transport_id': fields.many2one('kg.transport','Transport'),
	'contact_person': fields.char('Contact Person', size=128),
	'landmark': fields.char('Landmark', size=128),
	#~ 'partner_state': fields.selection([('draft','Draft'),('confirm','WFA'),('approve','Approved'),('reject','Rejected'),('cancel','Cancelled')],'Status'),
	'group_flag': fields.boolean('Is Group Company'),
	'delivery_id': fields.many2one('kg.delivery.master','Delivery Type'),
	#'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]),
	
	'con_designation': fields.char('Designation'),
	'con_whatsapp': fields.char('Whatsapp No'),
	#~ 'acc_number': fields.char('Whatsapp No'),
	#~ 'bank_name': fields.char('Whatsapp No'),
	#~ 'bank_bic': fields.char('Whatsapp No'),
	'delivery_ids':fields.one2many('kg.delivery.address', 'src_id', 'Delivery Address'),
	'billing_ids':fields.one2many('kg.billing.address', 'bill_id', 'Billing Address'),
	'consult_ids':fields.one2many('kg.consultant.fee', 'consult_id', 'Consultant Fees'),
	'dealer': fields.boolean('Dealer'),
	'economic_category': fields.selection([('budget','Budget'),('loyalty','Loyalty')],'Economic Category'),
	'sector': fields.selection([('cp','CP'),('ip','IP'),('both','Both')],'Marketing Division'),
	'industry_id': fields.many2one('kg.industry.master','Sector'),
	'dealer_id': fields.many2one('res.partner','Dealer Name',domain=[('dealer','=',True)]),
	'remark': fields.text('Approve/Reject'),
	'cancel_remark': fields.text('Cancel Remarks'),
	'modify': fields.function(_get_modify, string='Modify', method=True, type='char', size=3),
	'user_ref_id': fields.many2one('res.users','User Name'),
	'adhar_id': fields.char('Adhar ID'),
	'contractor': fields.boolean('Contractor'),
	'tin_flag': fields.boolean('TIN Flag'),
	'mobile_2': fields.char('Mobile2',size=12),
	'email_applicable': fields.selection([('yes','Yes'),('no','No')],'Email Applicable'),
	'sms_applicable': fields.selection([('yes','Yes'),('no','No')],'SMS Applicable'),
	
	## Entry Info
	
	'creation_date': fields.datetime('Created Date',readonly=True),
	'created_by': fields.many2one('res.users', 'Created by',readonly=True),
	'confirmed_date': fields.datetime('Confirmed Date',readonly=True),
	'confirmed_by': fields.many2one('res.users','Confirmed By',readonly=True),
	'rej_user_id': fields.many2one('res.users', 'Rejected By', readonly=True),
	'reject_date': fields.datetime('Reject Date', readonly=True),
	'approved_date': fields.datetime('Approved Date',readonly=True),
	'approved_by': fields.many2one('res.users','Approved By',readonly=True),
	'cancel_date': fields.datetime('Cancelled Date', readonly=True),
	'cancel_user_id': fields.many2one('res.users', 'Cancelled By', readonly=True),
	'updated_date': fields.datetime('Last Updated Date',readonly=True),
	'updated_by': fields.many2one('res.users','Last Updated By',readonly=True),
	
	}
	
	_defaults = {
	  
	  'is_company': True,
	  'creation_date': lambda * a: time.strftime('%Y-%m-%d %H:%M:%S'),
	  'created_by': lambda obj, cr, uid, context: uid,
	  'partner_state': 'draft',
	  'modify': 'no',
	  'tin_flag': False,
	  'company_type': 'company',
		 
	}

	def onchange_city(self, cr, uid, ids, city_id, context=None):
		if city_id:
			state_id = self.pool.get('res.city').browse(cr, uid, city_id, context).state_id.id
			return {'value':{'state_id':state_id}}
		return {}
	
	def onchange_zip(self,cr,uid,ids,zip,context=None):
		if len(str(zip)) in (6,7,8):
			value = {'zip':zip}
		else:
			raise osv.except_osv(_('Check zip number !!'),
				_('zip should contain 6-8 digit numerics. Else system not allow to save. !!'))
		if zip.isdigit() == False:
			raise osv.except_osv(_('Check zip number !!'),
				_('Please enter numeric values !!'))
		return {'value': value}
			
	#~ def onchange_tin_cst(self,cr,uid,ids,tin_no,cst_no,context=None):
		#~ if tin_no:
			#~ if len(str(tin_no)) == 11:
				#~ value = {'tin_no':tin_no}
			#~ else:
				#~ raise osv.except_osv(_('Check TIN number !!'),
					#~ _('Please enter 11 digit number !!'))
		#~ if cst_no:
			#~ if len(str(cst_no)) == 11:
				#~ value = {'cst_no':cst_no}
			#~ else:
				#~ raise osv.except_osv(_('Check CST number !!'),
					#~ _('Please enter 11 digit number !!'))
		#~ return {'value': value}
			
	def confirm_partner(self, cr, uid, ids, context=None): 
		rec = self.browse(cr, uid, ids[0])
		if rec.partner_state == 'draft':
			self.write(cr, uid, ids, {'partner_state': 'confirm','confirmed_by':uid,'confirmed_date': time.strftime('%Y-%m-%d %H:%M:%S')})
		return True
		
	def reject_partner(self, cr, uid, ids, context=None): 
		rec = self.browse(cr, uid, ids[0])
		if rec.partner_state == 'confirm':
			if rec.remark:
				self.write(cr, uid, ids, {'partner_state': 'reject','update_user_id':uid,'reject_date': time.strftime('%Y-%m-%d %H:%M:%S')})
			else:
				raise osv.except_osv(_('Rejection remark is must !!'),
					_('Enter rejection remark in remark field !!'))
		return True
		
	def approve_partner(self, cr, uid, ids, context=None): 
		rec = self.browse(cr, uid, ids[0])
		if rec.partner_state == 'confirm':
			self.write(cr, uid, ids, {'partner_state': 'approve','approved_by':uid,'approved_date': time.strftime('%Y-%m-%d %H:%M:%S')})
		return True

	def entry_draft(self,cr,uid,ids,context=None):
		rec = self.browse(cr, uid, ids[0])
		if rec.partner_state == 'approve':
			self.write(cr, uid, ids, {'partner_state': 'draft'})
		return True
		
	def entry_cancel(self,cr,uid,ids,context=None):
		rec = self.browse(cr,uid,ids[0])
		if rec.partner_state == 'approve':
			if rec.cancel_remark:
				self.write(cr, uid, ids, {'partner_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 unlink(self,cr,uid,ids,context=None):
		unlink_ids = []		
		for rec in self.browse(cr,uid,ids):	
			if rec.partner_state != 'draft':			
				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):
		print"valsssssS",vals
		#if len(str(vals['zip'])) == 6:
		#	pass
		#else:
		#	raise osv.except_osv(_('Check zip number !!'),
		#		_('Please enter six digit number !!'))
		vals.update({'updated_date': time.strftime('%Y-%m-%d %H:%M:%S'),'updated_by':uid})
		return super(kg_partner, self).write(cr, uid, ids, vals, context)
	
	def _check_zip(self, cr, uid, ids, context=None):		
		rec = self.browse(cr, uid, ids[0])
		if rec.zip:
			if len(str(rec.zip)) in (6,7,8) and rec.zip.isdigit() == True:
				return True
		else:
			return True
		return False
		
	def _check_tin(self, cr, uid, ids, context=None):		
		rec = self.browse(cr, uid, ids[0])
		if rec.tin_no:
			if len(str(rec.tin_no)) == 11 and rec.tin_no.isdigit() == True:
				return True
		else:
			return True
		return False
		
	def _check_cst(self, cr, uid, ids, context=None):		
		rec = self.browse(cr, uid, ids[0])
		if rec.cst_no:
			if len(str(rec.cst_no)) == 11 and rec.cst_no.isdigit() == True:
				return True
		else:
			return True
		return False
		
	def _check_vat(self, cr, uid, ids, context=None):		
		rec = self.browse(cr, uid, ids[0])
		if rec.vat_no:
			if len(str(rec.vat_no)) == 15:
				return True
		else:
			return True
		return False
	
	def _check_phone(self, cr, uid, ids, context=None):		
		rec = self.browse(cr, uid, ids[0])
		if rec.phone:
			if len(str(rec.phone)) in (8,9,10,11,12,13,14,15) and rec.phone.isdigit() == True:
				return True
		else:
			return True
		return False
	
	def _validate_email(self, cr, uid, ids, context=None):
		rec = self.browse(cr,uid,ids[0]) 
		if rec.email==False:
			return True
		else:
			if re.match("^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$", rec.email) != None:
				return True
			else:
				raise osv.except_osv('Invalid Email', 'Please enter a valid email address')   
				
	def _check_website(self, cr, uid, ids, context=None):
		rec = self.browse(cr, uid, ids[0])
		if rec.website != False:
			#~ if re.match('www?.(?:www)?(?:[\w-]{2,255}(?:\.\w{2,6}){1,2})(?:/[\w&%?#-]{1,300})?',rec.website):
			if re.match('www.(?:www)?(?:[\w-]{2,255}(?:\.\w{2,6}){1,2})(?:/[\w&%?#-]{1,300})?',rec.website):
				return True
			else:
				return False
		return True

	def _check_ifsc(self, cr, uid, ids, context=None):
		rec = self.browse(cr, uid, ids[0])
		if rec.bank_ids:
			for item in rec.bank_ids:
				if item.bank_bic:
					if len(str(item.bank_bic)) == 11:
						return True
				else:
					return True
		else:
			return True
		return False
			
	def _check_acc_no(self, cr, uid, ids, context=None):
		rec = self.browse(cr, uid, ids[0])
		if rec.bank_ids:
			for item in rec.bank_ids:
				if item.acc_number:
					if len(str(item.acc_number)) in (6,7,8,9,10,11,12,13,14,15,16,17,18) and item.acc_number.isdigit() == True:
						return True
				else:
					return True
		else:
			return True
		return False
		
	def _check_mobile_no(self, cr, uid, ids, context=None):		
		rec = self.browse(cr, uid, ids[0])
		if rec.mobile:
			if len(str(rec.mobile)) in (10,11,12) and rec.mobile.isdigit() == True:
				return True
		else:
			return True
		return False
	
	def _name_validate(self, cr, uid,ids, context=None):
		rec = self.browse(cr,uid,ids[0])
		res = True
		data=''
		if rec.name:
			partner_name = rec.name
			name=partner_name.upper()
			if rec.customer == True:
				cr.execute(""" select upper(name) from res_partner where upper(name) = '%s' and customer = True """ %(name))
				data = cr.dictfetchall()
			elif rec.supplier == True:
				cr.execute(""" select upper(name) from res_partner where upper(name) = '%s' and supplier = True """ %(name))
				data = cr.dictfetchall()
			elif rec.dealer == True:
				cr.execute(""" select upper(name) from res_partner where upper(name) = '%s' and dealer = True """ %(name))
				data = cr.dictfetchall()
			if len(data) > 1:
				res = False
			else:
				res = True
		return res
	
	def _unique_tin(self, cr, uid,ids, context=None):
		rec = self.browse(cr,uid,ids[0])
		res = True
		if rec.tin_no:
			tin_no = rec.tin_no
			name = tin_no.upper()			
			cr.execute(""" select tin_no from res_partner where tin_no = '%s' """ %(name))
			data = cr.dictfetchall()	
			if len(data) > 1:
				res = False
			else:
				res = True				
		return res
	
	def _spl_name(self, cr, uid, ids, context=None):		
		rec = self.browse(cr, uid, ids[0])
		if rec.name:
			name_special_char = ''.join(c for c in rec.name if c in '!@#$%^~*{}?+/=')
			if name_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not Allowed in Name!'))
		if rec.adhar_id:
			adhar_special_char = ''.join(c for c in rec.adhar_id if c in '!@#$%^~*{}?+/=')
			if adhar_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not Allowed in Adhar ID!'))
		if rec.pan_no:	
			pan_special_char = ''.join(c for c in rec.pan_no if c in '!@#$%^~*{}?+/=')
			if pan_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not Allowed in PAN!'))
		if rec.gst_no:	
			gst_special_char = ''.join(c for c in rec.gst_no if c in '!@#$%^~*{}?+/=')
			if gst_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not Allowed in GST!'))
		if rec.tan_no:
			tan_special_char = ''.join(c for c in rec.tan_no if c in '!@#$%^~*{}?+/=')
			if tan_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not Allowed in TAN!'))
		if rec.cst_no:
			cst_special_char = ''.join(c for c in rec.cst_no if c in '!@#$%^~*{}?+/=')
			if cst_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not in CST!'))
		if rec.vat_no:
			vat_special_char = ''.join(c for c in rec.vat_no if c in '!@#$%^~*{}?+/=')
			if vat_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not in VAT!'))
		if rec.cheque_in_favour:
			cheque_special_char = ''.join(c for c in rec.cheque_in_favour if c in '!@#$%^~*{}?+/=')
			if cheque_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not in Cheque in Favour Of!'))
		if rec.contact_person:
			contact_special_char = ''.join(c for c in rec.contact_person if c in '!@#$%^~*{}?+/=')
			if contact_special_char:
				raise osv.except_osv(_('Warning!'),
					_('Special Character Not in Contact Person!'))
			return True
		else:
			return True
		return False
		
	_constraints = [
	
		(_check_zip,'ZIP should contain 6-8 digit numerics. Else system not allow to save.',['ZIP']),
		(_check_tin,'TIN No. should contain 11 digit numerics. Else system not allow to save.',['TIN']),
		(_check_cst,'CST No. should contain 11 digit numerics. Else system not allow to save.',['CST']),
		(_check_vat,'VAT No. should contain 15 letters. Else system not allow to save.',['VAT']),
		(_validate_email,'Check Email !',['']),
		(_check_website,'Check Website !',['Website']),
		(_check_phone,'Phone No. should contain 8-15 digit numerics. Else system not allow to save.',['Phone']),
		(_check_ifsc,'IFSC should contain 11 letters. Else system not allow to save.',['IFSC']),
		(_check_acc_no,'A/C No. should contain 6-18 digit numerics. Else system not allow to save.',['A/C No.']),
		(_check_mobile_no,'Mobile No. should contain 10-12 digit numerics. Else system not allow to save.',['Mobile']),
		(_name_validate, 'Name must be unique !!', ['Name']),		
		(_unique_tin, 'TIN must be unique !!', ['TIN']),
		(_spl_name, 'Special Character Not Allowed!', ['']),
		]
Beispiel #26
0
class crm_claim(osv.osv):
    """ Crm claim
    """
    _name = "crm.claim"
    _description = "Claim"
    _order = "priority,date desc"
    _inherit = ['mail.thread']

    def _get_default_section_id(self, cr, uid, context=None):
        """ Gives default section by checking if present in the context """
        return self.pool.get('crm.lead')._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, [('sequence', '=', '1')],
                               context=context)

    _columns = {
        'id': fields.integer('ID', readonly=True),
        'name': fields.char('Claim Subject', size=128, required=True),
        'active': fields.boolean('Active'),
        'action_next': fields.char('Next Action', size=200),
        'date_action_next': fields.datetime('Next Action Date'),
        'description': fields.text('Description'),
        'resolution': fields.text('Resolution'),
        'create_date': fields.datetime('Creation Date' , readonly=True),
        'write_date': fields.datetime('Update Date' , readonly=True),
        'date_deadline': fields.date('Deadline'),
        'date_closed': fields.datetime('Closed', readonly=True),
        'date': fields.datetime('Claim Date', select=True),
        'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models),
        'categ_id': fields.many2one('crm.case.categ', 'Category', \
                            domain="[('section_id','=',section_id),\
                            ('object_id.model', '=', 'crm.claim')]"                                                                   ),
        'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
        'type_action': fields.selection([('correction','Corrective Action'),('prevention','Preventive Action')], 'Action Type'),
        'user_id': fields.many2one('res.users', 'Responsible'),
        'user_fault': fields.char('Trouble Responsible', size=64),
        'section_id': fields.many2one('crm.case.section', 'Sales Team', \
                        select=True, help="Responsible sales team."\
                                " Define Responsible user and Email account for"\
                                " mail gateway."),
        'company_id': fields.many2one('res.company', 'Company'),
        'partner_id': fields.many2one('res.partner', 'Partner'),
        '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"),
        'email_from': fields.char('Email', size=128, help="Destination email for email gateway."),
        'partner_phone': fields.char('Phone', size=32),
        'stage_id': fields.many2one ('crm.claim.stage', 'Stage', track_visibility='onchange',
                domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
        'cause': fields.text('Root Cause'),
    }

    _defaults = {
        'user_id':
        lambda s, cr, uid, c: uid,
        'section_id':
        lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
        'date':
        fields.datetime.now,
        'company_id':
        lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(
            cr, uid, 'crm.case', context=c),
        'priority':
        lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
        'active':
        lambda *a: 1,
        'stage_id':
        lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c)
    }

    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:
            - section_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
        section_ids = []
        if section_id:
            section_ids.append(section_id)
        for claim in cases:
            if claim.section_id:
                section_ids.append(claim.section_id.id)
        # 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))
        search_domain.append(('case_default', '=', True))
        # AND with the domain in parameter
        search_domain += list(domain)
        # perform search, return the first found
        stage_ids = self.pool.get('crm.claim.stage').search(cr,
                                                            uid,
                                                            search_domain,
                                                            order=order,
                                                            context=context)
        if stage_ids:
            return stage_ids[0]
        return False

    def onchange_partner_id(self,
                            cr,
                            uid,
                            ids,
                            partner_id,
                            email=False,
                            context=None):
        """This function returns value of partner address based on partner
           :param email: ignored
        """
        if not partner_id:
            return {'value': {'email_from': False, 'partner_phone': False}}
        address = self.pool.get('res.partner').browse(cr,
                                                      uid,
                                                      partner_id,
                                                      context=context)
        return {
            'value': {
                'email_from': address.email,
                'partner_phone': address.phone
            }
        }

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {}
        if vals.get('section_id') and not context.get('default_section_id'):
            context['default_section_id'] = vals.get('section_id')

        # context: no_log, because subtype already handle this
        return super(crm_claim, self).create(cr, uid, vals, context=context)

    def copy(self, cr, uid, id, default=None, context=None):
        claim = self.browse(cr, uid, id, context=context)
        default = dict(default or {},
                       stage_id=self._get_default_stage_id(cr,
                                                           uid,
                                                           context=context),
                       name=_('%s (copy)') % claim.name)
        return super(crm_claim, self).copy(cr,
                                           uid,
                                           id,
                                           default,
                                           context=context)

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

    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),
        }
        if msg.get('priority'):
            defaults['priority'] = msg.get('priority')
        defaults.update(custom_values)
        return super(crm_claim, self).message_new(cr,
                                                  uid,
                                                  msg,
                                                  custom_values=defaults,
                                                  context=context)
Beispiel #27
0
class closing_stock(osv.osv):

    _name = "closing_stock"
    _description = "closing_stock"

    _columns = {
        
        
        'date':fields.datetime('Date'),
        
        'line_ids': fields.one2many('closing_stock.line','closing_id','Line Id', size=128),
        
    }
    
    def load_stock(self, cr, uid, ids, context=None):
        cr.execute("""delete from closing_stock_line""")
        product_list = []
        
        psql1 = """select distinct product_id from stock_move """    
        cr.execute(psql1)
        pdata = cr.dictfetchall()
        
        rec = self.browse(cr, uid, ids[0])
        
        for i in pdata:
            
            pro_rec = self.pool.get('product.product').browse(cr,uid,i['product_id'])
            product_list.append(pro_rec)
        
        for item in product_list:
            in_qty = 0.00
            out_qty = 0.00
           
            in_move_obj = self.pool.get('stock.move').search(cr,uid,[('location_dest_id','=',23),('product_id','=',item.id)])
            in_move_rec = self.pool.get('stock.move').browse(cr,uid,in_move_obj)
            
            if in_move_rec:
                for i in in_move_rec:
                    in_qty +=i.product_qty
                    
           
            out_move_obj = self.pool.get('stock.move').search(cr,uid,[('location_id','=',23),('product_id','=',item.id)])
            out_move_rec = self.pool.get('stock.move').browse(cr,uid,out_move_obj)
            
            if out_move_rec:
                for j in out_move_rec:
                    out_qty +=j.product_qty
           
            close_qty = in_qty - out_qty
            
           
            if close_qty > 0:
				
                
                self.pool.get('closing_stock.line').create(cr, uid, {
                            'closing_id': rec.id,
                            'product_id': item.id,
                            'uom': item.uom_id.id,
                            
                            'receive_qty':in_qty,
                            'issued_qty': out_qty,
                            'closing_stocks':close_qty,
                           
    
                        })
        return True 
Beispiel #28
0
    class reportx(osv.Model):
        _name = "cash.count.reportx"
        _rec_name = 'number'

        def _compute_total(self, cr, uid, ids, fieldnames, args, context=None):
            context = context or {}
            result = dict()
            for record in self.browse(cr, uid, ids, context=context):
                total = 0.0
                for line in record.lines:
                    total += line.end_balance
                result[record.id] = total
            return result

        def create_from_ui(self, cr, uid, data, context=None):
            context = context or {}
            cs_id = data.get('cashier_session_id')
            cs_obj = self.pool.get('cash.count.cashier.session')
            cs = cs_obj.browse(cr, uid, cs_id, context=context)
            lines = []
            for line in data.get('lines'):
                for s in cs.session_id.statement_ids:
                    if s.journal_id.id == line[
                            'journal_id'] and s.instrument_id.id == line[
                                'instrument_id']:
                        lines.append((0, 0, {
                            'statement_id': s.id,
                            'end_balance': line['amount']
                        }))
            data['lines'] = lines
            data['date'] = time.strftime('%Y-%m-%d %H:%M:%S')
            r_id = self.create(cr, uid, data, context=context)
            cs_obj.write(cr, uid, cs_id, {'reportx_id': r_id}, context=context)
            wf_service = netsvc.LocalService("workflow")
            wf_service.trg_validate(uid, 'cash.count.cashier.session', cs_id,
                                    'close', cr)
            return r_id

        _columns = {
            'number':
            fields.char('Report Number', size=50),
            'date':
            fields.datetime('Date', readonly=True),
            'cashier_session_id':
            fields.many2one('cash.count.cashier.session', 'Cashier Session'),
            'cashier_id':
            fields.related('cashier_session_id',
                           'cashier_id',
                           type='many2one',
                           relation='hr.employee',
                           string='Cashier'),
            'pos_session_id':
            fields.many2one('pos.session', 'PoS Session'),
            'printer_serial':
            fields.char('Printer Serial', size=64, required=True),
            'printer_id':
            fields.many2one('fiscal_printer.printer', 'Printer'),
            'lines':
            fields.one2many('cash.count.reportx.line', 'reportx_id',
                            'Report Details'),
            'total':
            fields.function(_compute_total,
                            type='float',
                            string='Total',
                            digits_compute=dp.get_precision('Account')),
        }
class import_ftp_ajri(osv.osv):
	_name 		= "reliance.import_ftp_ajri"
	_rec_name 	= "input_file"

	_columns 	= {
		'date_start'	: fields.datetime('Date Start'),
		'date_end'		: fields.datetime('Date End'),
		'user_id'		: fields.many2one('res.users', 'Users'),
		'input_file'	: fields.char('Input File'),
		'total_records'	: fields.integer('Total Records'),
		'notes'			: fields.char('Notes'),
	}

	_defaults = {
		'user_id'	: lambda obj, cr, uid, context: uid,
	}


	###########################################################
	# dipanggil dari cron job
	###########################################################
	def cron_process(self, cr, uid, context=None):
		_logger.warning('running FTP AJRI cron_process')
		self.check_new_files(cr, uid, [], context=context)
		return True


	###########################################################
	#
	# is there new files on the ftp upload folder ?
	# called from cron job
	# if type=zip: unzip
	# process the extracted CSV 
	###########################################################
	def check_new_files(self, cr, uid, ids, context=None):
		ftp_utils = ftp.ftp_utils()

		ftp_ajri_folder = self.pool.get('ir.config_parameter').get_param(cr, uid, 'ftp_ajri_folder')

		ftp_utils.check_done_folder(ftp_ajri_folder)

		if context==None:
			context={}
		context.update({'date_start':time.strftime('%Y-%m-%d %H:%M:%S')})


		# search and extract ZIP and move zip to done folder
		# zip_files = glob.glob(ftp_ajri_folder + '/*.zip')
		zip_files = ftp_utils.insensitive_glob(ftp_ajri_folder + '/*.zip')

		for f in zip_files:
			if zipfile.is_zipfile(f):
				ftp_utils.unzip(f, ftp_ajri_folder)
				done = ftp_utils.done_filename(cr, uid, f, context=context)
				shutil.move(f, done)
			else:
				_logger.error('wrong zip file')

		# search CSV
		# csv_files = glob.glob(ftp_ajri_folder + '/*.csv')
		csv_files = ftp_utils.insensitive_glob(ftp_ajri_folder + '/*.csv')

		for csv_file in csv_files:
			if csv_file.upper().find('AJRI') != -1:
				self.insert_ajri_customer(cr, uid, csv_file, context=context)


		return 


	###########################################################
	# read the CSV into ls partner
	###########################################################
	def insert_ajri_customer(self, cr, uid, csv_file, context=None):
		_logger.warning('importing csv data insert_ajri_customer')
		ftp_utils = ftp.ftp_utils()
		import_ajri = self.pool.get('reliance.import_ajri')

		cron_obj = self.pool.get('ir.cron')
		cron_id = cron_obj.search(cr, uid,
			[('name','=', "Auto Import AJRI Partner")], context=context)
		if not cron_id:
			raise osv.except_osv(_('error'),_("no cron job Auto Import AJRI Partner") )

		fields_map = [
			"nomor_polis"			,
			"nama_pemegang"			,
			"nomor_partisipan"		,
			"nama_partisipan"		,
			"produk"				,
			"tgl_lahir"				,
			"tgl_mulai"				,
			"tgl_selesai"			,
			"status"				,
			"up"					,
			"total_premi"			,
			"status_klaim"			,
			"status_bayar"			,
			"tgl_bayar"				,
			"klaim_disetujui"		,
		]

		
		i = ftp_utils.read_csv_insert(cr, uid, csv_file, fields_map, import_ajri, 
			delimiter=DELIMITER, quotechar=QUOTECHAR,
			cron_id=cron_id, cron_obj=cron_obj,
			context=context)
		
		if isinstance(i, dict):
			self.create(cr, uid, i, context=context )
			cr.commit()
			return

		# move csv_file to processed folder
		done = ftp_utils.done_filename(cr, uid, csv_file, context=context)
		shutil.move(csv_file, done)

		data = {
			'date_start' : context.get('date_start',False),
			'date_end' : time.strftime('%Y-%m-%d %H:%M:%S'),
			'input_file' : csv_file,
			'total_records' : i,
			'notes'	: '%s moved to %s' % (csv_file, done),
		}
		self.create(cr, uid, data, context=context )
		cr.commit()

		return 
Beispiel #30
0
class cashier_session(osv.Model):

    _name = "cash.count.cashier.session"

    SESSION_STATE = [
        ('opened', 'In Progress'),  # Signal closing
        ('closed', 'Closed & Posted'),
    ]

    def login(self, cr, uid, username, password, context=None):
        context = context or {}
        obj = self.pool.get('hr.employee')
        criteria = [('username', '=', username), ('password', '=', password)]
        if context.get('manager'):
            criteria.append(('role', '=', 'manager'))
        ids = obj.search(cr, uid, criteria, context=context)
        if ids:
            return ids[0]
        else:
            return False

    def wkf_action_open(self, cr, uid, ids, context=None):
        context = context or {}
        values = {'opening_date': time.strftime('%Y-%m-%d %H:%M:%S')}
        return self.write(cr, uid, ids, values, context=context)

    def open_session(self,
                     cr,
                     uid,
                     session_id,
                     username,
                     password,
                     context=None):
        context = context or {}
        cashier_id = self.login(cr, uid, username, password, context=context)
        if cashier_id:
            c = [('session_id', '=', session_id), ('state', '=', 'opened')]
            session_ids = self.search(cr, uid, c, context=context)
            if len(session_ids) == 0:
                values = {'session_id': session_id, 'cashier_id': cashier_id}
                s_id = self.create(cr, uid, values, context=context)
                session = self.read(cr, uid, s_id, context=context)
                result = {'status': 0, 'session': session}
            else:
                result = {
                    'status': 1,
                    'msg': _("You can open only one session at a time")
                }
        else:
            result = {'status': 1, 'msg': _("Wrong user name or password")}
        return result

    def close_session(self, cr, uid, session_id, context=None):
        context = context or {}
        session = self.browse(cr, uid, session_id, context=context)
        if session.state == 'opened':
            wf_service = netsvc.LocalService("workflow")
            wf_service.trg_validate(uid, 'cash.count.cashier.session',
                                    session_id, 'close', cr)
            return True
        return False

    def wkf_action_close(self, cr, uid, ids, context=None):
        context = context or {}
        values = {'closing_date': time.strftime('%Y-%m-%d %H:%M:%S')}
        values.update({'state': 'closed'})
        return self.write(cr, uid, ids, values, context=context)

    def unlock_session(self,
                       cr,
                       uid,
                       session_id,
                       username,
                       password,
                       context=None):
        context = context or {}
        cashier_id = self.login(cr, uid, username, password, context=context)
        if cashier_id:
            c = [('session_id', '=', session_id), ('state', '=', 'opened'),
                 ('cashier_id', '=', cashier_id)]
            session_ids = self.search(cr, uid, c, context=context)
            if len(session_ids) == 1:
                return True

        return False

    def create(self, cr, uid, values, context=None):
        context = context or {}
        s_obj = self.pool.get('pos.session')
        s_id = values.get('session_id')
        session = s_obj.browse(cr, uid, s_id, context=context)
        values.update({'name': session.sequence_id._next()})
        return super(cashier_session, self).create(cr,
                                                   uid,
                                                   values,
                                                   context=context)

    _columns = {
        'name':
        fields.char('Cashier Session ID',
                    size=32,
                    required=True,
                    readonly=True),
        'session_id':
        fields.many2one('pos.session', 'Pos Session', required=True),
        'cashier_id':
        fields.many2one('hr.employee', 'Cashier', required=True),
        'opening_date':
        fields.datetime('Opening Date', readonly=True),
        'closing_date':
        fields.datetime('Closing Date', readonly=True),
        'state':
        fields.selection(SESSION_STATE,
                         'Status',
                         required=True,
                         readonly=True,
                         select=1),
        'reportx_id':
        fields.many2one('cash.count.reportx', 'Report X'),
    }

    _defaults = {
        'state': 'opened',
    }

    _order = "name"

    class reportx(osv.Model):
        _name = "cash.count.reportx"
        _rec_name = 'number'

        def _compute_total(self, cr, uid, ids, fieldnames, args, context=None):
            context = context or {}
            result = dict()
            for record in self.browse(cr, uid, ids, context=context):
                total = 0.0
                for line in record.lines:
                    total += line.end_balance
                result[record.id] = total
            return result

        def create_from_ui(self, cr, uid, data, context=None):
            context = context or {}
            cs_id = data.get('cashier_session_id')
            cs_obj = self.pool.get('cash.count.cashier.session')
            cs = cs_obj.browse(cr, uid, cs_id, context=context)
            lines = []
            for line in data.get('lines'):
                for s in cs.session_id.statement_ids:
                    if s.journal_id.id == line[
                            'journal_id'] and s.instrument_id.id == line[
                                'instrument_id']:
                        lines.append((0, 0, {
                            'statement_id': s.id,
                            'end_balance': line['amount']
                        }))
            data['lines'] = lines
            data['date'] = time.strftime('%Y-%m-%d %H:%M:%S')
            r_id = self.create(cr, uid, data, context=context)
            cs_obj.write(cr, uid, cs_id, {'reportx_id': r_id}, context=context)
            wf_service = netsvc.LocalService("workflow")
            wf_service.trg_validate(uid, 'cash.count.cashier.session', cs_id,
                                    'close', cr)
            return r_id

        _columns = {
            'number':
            fields.char('Report Number', size=50),
            'date':
            fields.datetime('Date', readonly=True),
            'cashier_session_id':
            fields.many2one('cash.count.cashier.session', 'Cashier Session'),
            'cashier_id':
            fields.related('cashier_session_id',
                           'cashier_id',
                           type='many2one',
                           relation='hr.employee',
                           string='Cashier'),
            'pos_session_id':
            fields.many2one('pos.session', 'PoS Session'),
            'printer_serial':
            fields.char('Printer Serial', size=64, required=True),
            'printer_id':
            fields.many2one('fiscal_printer.printer', 'Printer'),
            'lines':
            fields.one2many('cash.count.reportx.line', 'reportx_id',
                            'Report Details'),
            'total':
            fields.function(_compute_total,
                            type='float',
                            string='Total',
                            digits_compute=dp.get_precision('Account')),
        }

    class reportx_line(osv.Model):
        _name = "cash.count.reportx.line"

        _columns = {
            'reportx_id':
            fields.many2one('cash.count.reportx', 'Report X'),
            'statement_id':
            fields.many2one('account.bank.statement', 'Statement'),
            'journal_id':
            fields.related('statement_id',
                           'journal_id',
                           type='many2one',
                           relation='account.journal',
                           string='Journal'),
            'instrument_id':
            fields.related('statement_id',
                           'instrument_id',
                           type='many2one',
                           relation='payment_instrument.instrument',
                           string='Instrument'),
            'end_balance':
            fields.float('Ending Balance',
                         required=True,
                         digits_compute=dp.get_precision('Account')),
        }
Beispiel #31
0
								"during order shipment and invoice, else it won't."),
		'language':fields.selection(_lang_get, "Default Language", help="Selected language is loaded in the system, "
							"all documents related to this contact will be synched in this language."),
		'category':fields.many2one('product.category', "Default Category", help="Selected Category will be set default category for odoo's product, "
							"in case when magento product doesn\'t belongs to any catgeory."),
		'state':fields.selection([('enable','Enable'),('disable','Disable')],'Status', help="status will be consider during order invoice, "
							"order delivery and order cancel, to stop asynchronous process at other end.", size=100),
		'inventory_sync':fields.selection([	('enable','Enable'),
											('disable','Disable')],
								'Inventory Update', 
								help="If Enable, Invetory will Forcely Update During Product Update Operation.", size=100),
		'warehouse_id':fields.many2one('stock.warehouse','Warehouse', 
									help="Used During Inventory Synchronization From Magento to Odoo."),
		'location_id': fields.related('warehouse_id', 'lot_stock_id', type='many2one', relation='stock.location', string='Location'),
		
		'create_date':fields.datetime('Created Date'),
		'correct_mapping':fields.boolean('Correct Mapping'),
		'route_id':fields.many2one('stock.location.route','Route', 
									help="Used During Sale Order From Magento to Odoo."),
	}
	_defaults = {
		'correct_mapping':True,
		'instance_name':_default_instance_name,
		'active':lambda *a: 1,	
		'auto_ship':lambda *a: 1,
		'auto_invoice':lambda *a: 1,
		'credential':lambda *a: 1,
		'language': api.model(lambda self: self.env.lang),
		'category':_default_category,
		'state':'enable',
		'inventory_sync':'enable',
Beispiel #32
0
class stock_production_lot(osv.osv):
    _inherit = 'stock.production.lot'

    def _get_date(dtype):
        """Return a function to compute the limit date for this type"""
        def calc_date(self, cr, uid, context=None):
            """Compute the limit date for a given date"""
            if context is None:
                context = {}
            if not context.get('product_id', False):
                date = False
            else:
                product = openerp.registry(
                    cr.dbname)['product.product'].browse(
                        cr, uid, context['product_id'])
                duration = getattr(product, dtype)
                # set date to False when no expiry time specified on the product
                date = duration and (datetime.datetime.today() +
                                     datetime.timedelta(days=duration))
            return date and date.strftime('%Y-%m-%d %H:%M:%S') or False

        return calc_date

    _columns = {
        'life_date':
        fields.datetime(
            'End of Life Date',
            help=
            'This is the date on which the goods with this Serial Number may become dangerous and must not be consumed.'
        ),
        'use_date':
        fields.datetime(
            'Best before Date',
            help=
            'This is the date on which the goods with this Serial Number start deteriorating, without being dangerous yet.'
        ),
        'removal_date':
        fields.datetime(
            'Removal Date',
            help=
            'This is the date on which the goods with this Serial Number should be removed from the stock.'
        ),
        'alert_date':
        fields.datetime(
            'Alert Date',
            help=
            "This is the date on which an alert should be notified about the goods with this Serial Number."
        ),
    }

    # Assign dates according to products data
    def create(self, cr, uid, vals, context=None):
        context = dict(context or {})
        context['product_id'] = vals.get('product_id',
                                         context.get('default_product_id'))
        return super(stock_production_lot, self).create(cr,
                                                        uid,
                                                        vals,
                                                        context=context)

    _defaults = {
        'life_date': _get_date('life_time'),
        'use_date': _get_date('use_time'),
        'removal_date': _get_date('removal_time'),
        'alert_date': _get_date('alert_time'),
    }
Beispiel #33
0
        myids = self.search(cr, uid, [], context=context)
        for user in self.browse(cr,uid,myids,context=context):
            res = user.counter +1;
            isTrue =   self.write(cr, uid, user.id, {'counter': res}, context=context)
        return isTrue

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

class saas_server(osv.osv):
    _inherit = ['mail.thread']
    _name = "saas.server"
class travel_journey(orm.Model):
    """Journey of travel"""
    _name = 'travel.journey'
    _description = _(__doc__)
    _journey_type_classes = {}

    @staticmethod
    def _check_dep_arr_dates(departure, arrival):
        return not departure or not arrival or departure <= arrival

    def _estimate_datetime(self, cr, uid, ids, field_name, context=None):
        """If there is no start date from journey, get it from travel"""
        if type(ids) in (int, long):
            ids = [ids]
        res = {}
        for journey in self.browse(cr, uid, ids, context=context):
            date = False
            if journey.type:
                try:
                    journey_class = self._journey_type_classes[journey.type]
                    date = journey_class._estimate_typed_date(
                        self, journey, field_name)
                except KeyError:
                    _logger.error(
                        _('Transportation type "%s" has not registered its '
                          'class in _journey_types, skipping its dates') %
                        journey.type)
                except AttributeError:
                    _logger.error(
                        _('Transportation type "%s" has not registered a '
                          '_estimate_typed_date() function, skipping its dates'
                          ) % journey.type)
            if field_name == 'date_start':
                date = (date or journey.departure
                        or journey.passenger_id.travel_id.date_start)
            elif field_name == 'date_stop':
                date = (date or journey.arrival
                        or journey.passenger_id.travel_id.date_stop)
            # Make sure every date is in datetime format and not simply date
            try:
                date = datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT)
            except ValueError:
                date = datetime.strptime(date, DEFAULT_SERVER_DATETIME_FORMAT)
            res[journey.id] = date
        return res

    def _estimate_date(self, cr, uid, ids, field_name, arg=None, context=None):
        datetimes = self._estimate_datetime(cr,
                                            uid,
                                            ids,
                                            field_name,
                                            context=context)
        return {
            i: datetimes[i].strftime(DEFAULT_SERVER_DATE_FORMAT)
            for i in datetimes
        }

    def _estimate_time(self, cr, uid, ids, field_name, arg=None, context=None):
        datetimes = self._estimate_datetime(cr,
                                            uid,
                                            ids,
                                            field_name,
                                            context=context)
        return {
            i: datetimes[i].strftime(DEFAULT_SERVER_TIME_FORMAT)
            for i in datetimes
        }

    def _inv_estimate_date(self,
                           cr,
                           uid,
                           ids,
                           field_name,
                           val,
                           arg,
                           context=None):
        """If there is no start date in journey, set it in travel"""
        if type(ids) in (int, long):
            ids = [ids]
        for journey in self.browse(cr, uid, ids, context=context):
            if journey.type:
                try:
                    journey_class = self._journey_type_classes[journey.type]
                    if (journey_class._inv_estimate_typed_date(
                            self, journey, field_name, val)):
                        continue
                except KeyError:
                    _logger.error(
                        _('Transportation type "%s" has not registered its '
                          'class in _journey_types, skipping its dates') %
                        journey.type)
                except AttributeError:
                    _logger.error(
                        _('Transportation type "%s" has not registered a '
                          '_inv_estimate_typed_date() function, skipping its '
                          'dates') % journey.type)
            if field_name == 'date_start':
                if journey.departure:
                    journey.write({'departure': val})
                elif journey.passenger_id.travel_id.date_start:
                    journey.passenger_id.travel_id.write({'date_start': val})
            elif field_name == 'date_stop':
                if journey.arrival:
                    journey.write({'arrival': val})
                elif journey.passenger_id.travel_id.date_stop:
                    journey.passenger_id.travel_id.write({'date_stop': val})

    def _default_class(self, cr, uid, context=None):
        ir_model_data = self.pool.get('ir.model.data')
        return ir_model_data.get_object_reference(
            cr,
            uid,
            'travel_journey',
            'travel_journey_class_directive',
        )[1]

    def _get_type(self, cr, uid, context=None):
        acc_type_obj = self.pool.get('travel.journey.type')
        ids = acc_type_obj.search(cr, uid, [])
        res = acc_type_obj.read(cr, uid, ids, ['code', 'name'], context)
        return [(r['code'], r['name']) for r in res]

    def create(self, cr, uid, vals, context=None):
        """If is_return is checked, create a return trip after."""
        def clear_return_vals(mVals):
            mVals = mVals.copy()
            if mVals.get('is_return'):
                mVals['is_return'] = False
                mVals['return_origin'] = False
                mVals['return_destination'] = False
                mVals['return_departure'] = False
                mVals['return_arrival'] = False
            return mVals

        return_vals = None
        if vals.get('is_return'):
            return_vals = clear_return_vals(vals.copy())
            return_vals['is_return'] = False
            return_vals['origin'] = vals.get('destination', False)
            return_vals['destination'] = vals.get('origin', False)
            return_vals['departure'] = vals.get('return_departure', False)
            return_vals['arrival'] = vals.get('return_arrival', False)
        vals = clear_return_vals(vals)
        res = super(travel_journey, self).create(cr,
                                                 uid,
                                                 vals,
                                                 context=context)
        if return_vals:
            super(travel_journey, self).create(cr,
                                               uid,
                                               return_vals,
                                               context=context)
        return res

    @staticmethod
    def on_change_return(cr, uid, ids, key, location, context=None):
        return {'value': {key: location}}

    def on_change_times(self,
                        cr,
                        uid,
                        ids,
                        departure,
                        arrival,
                        return_trip=False,
                        context=None):
        if self._check_dep_arr_dates(departure, arrival):
            return {}
        return {
            'value': {
                'return_arrival' if return_trip else 'arrival': False,
            },
            'warning': {
                'title':
                'Arrival after Departure',
                'message': ('Departure (%s) cannot be before Arrival (%s).' %
                            (departure, arrival)),
            },
        }

    def check_date_exists(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if not ids:  # pragma: no cover
            return False
        journey = self.browse(cr, uid, ids[0], context=context)
        return journey.departure or journey.arrival

    def check_date_exists_return(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if not ids:  # pragma: no cover
            return False
        journey = self.browse(cr, uid, ids[0], context=context)
        return (not journey.is_return or journey.return_departure
                or journey.return_arrival)

    def check_date(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if not ids:  # pragma: no cover
            return False
        journey = self.browse(cr, uid, ids[0], context=context)
        return self._check_dep_arr_dates(journey.departure, journey.arrival)

    def check_date_return(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if not ids:  # pragma: no cover
            return False
        journey = self.browse(cr, uid, ids[0], context=context)
        return self._check_dep_arr_dates(journey.return_departure,
                                         journey.return_arrival)

    def check_uom(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if not ids:  # pragma: no cover
            return False
        journey = self.browse(cr, uid, ids[0], context=context)
        return not (bool(journey.baggage_weight)
                    ^ bool(journey.baggage_weight_uom))

    def name_get(self, cr, uid, ids, context=None):
        return [(journey.id,
                 "%s (%s -> %s)" % (journey.passenger_id.partner_id.name,
                                    journey.origin.name_get()[0][1],
                                    journey.destination.name_get()[0][1]))
                for journey in self.browse(cr, uid, ids, context=context)]

    def company_get(self, cr, uid, ids, context=None):
        res = _("N/A")
        if type(ids) not in (int, long) and ids:
            ids = ids[0]
        journey = self.browse(cr, uid, ids, context=context)
        try:
            if journey.type:
                journey_class = self._journey_type_classes[journey.type]
                res = journey_class._company_typed_get(self, journey)
        except KeyError:
            _logger.error(
                _('Transportation type "%s" has not registered its '
                  'class in _journey_types, skipping its company') %
                journey.type)
        except AttributeError:
            _logger.error(
                _('Transportation type "%s" has not registered a '
                  '_estimate_typed_date() function, skipping its company') %
                journey.type)
        finally:
            return res

    def origin_get(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if ids:
            return self.browse(cr, uid, ids[0], context=context).origin

    def destination_get(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if ids:
            return self.browse(cr, uid, ids[0], context=context).destination

    def departure_date_get(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if ids:
            return self._estimate_date(cr,
                                       uid,
                                       ids,
                                       'date_start',
                                       context=context)[ids[0]]

    def arrival_date_get(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if ids:
            return self._estimate_date(cr,
                                       uid,
                                       ids,
                                       'date_stop',
                                       context=context)[ids[0]]

    def departure_time_get(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if ids:
            return self._estimate_time(cr,
                                       uid,
                                       ids,
                                       'date_start',
                                       context=context)[ids[0]]

    def arrival_time_get(self, cr, uid, ids, context=None):
        if type(ids) is not list:
            ids = [ids]
        if ids:
            return self._estimate_time(cr,
                                       uid,
                                       ids,
                                       'date_stop',
                                       context=context)[ids[0]]

    _columns = {
        'origin':
        fields.many2one('res.better.zip',
                        'Origin',
                        required='True',
                        help='Source city of travel.'),
        'destination':
        fields.many2one('res.better.zip',
                        'Destination',
                        required='True',
                        help='Destination city of travel.'),
        'return_origin':
        fields.many2one('res.better.zip', 'Origin (return)'),
        'return_destination':
        fields.many2one('res.better.zip', 'Destination (return)'),
        'is_return':
        fields.boolean('Return Trip', help='Generate a return trip'),
        'departure':
        fields.datetime('Desired Departure',
                        help='Desired date and time of departure.'),
        'arrival':
        fields.datetime('Desired Arrival',
                        help='Desired date and time of Arrival.'),
        'return_departure':
        fields.datetime('Desired Departure (return)'),
        'return_arrival':
        fields.datetime('Desired Arrival (return)'),
        'class_id':
        fields.many2one('travel.journey.class',
                        'Class',
                        required=True,
                        help='Desired class of voyage.'),
        'baggage_qty':
        fields.integer('Baggage Quantity',
                       help='Number of articles in baggage.'),
        'baggage_weight':
        fields.float('Baggage Weight', help='Weight of baggage.'),
        'baggage_weight_uom':
        fields.many2one('product.uom',
                        'Baggage Weight Unit of Measure',
                        help='Unit of Measure for Baggage Weight'),
        'comment':
        fields.text('Comments'),
        'passenger_id':
        fields.many2one('travel.passenger',
                        'Passenger',
                        required=True,
                        help='Passenger on this journey.'),
        'travel':
        fields.related('passenger_id',
                       'travel_name',
                       type='char',
                       string='Travel',
                       store=True),
        'state':
        fields.related('passenger_id',
                       'travel_state',
                       type='selection',
                       string='State',
                       store=True),
        'type':
        fields.selection(_get_type,
                         'Travel journey type',
                         help='Travel journey type.'),
        'reservation':
        fields.char('Reservation Number',
                    size=256,
                    help="Number of the ticket reservation."),
        'cancellation':
        fields.text('Cancellation', help='Notes on cancellation.'),
        'date_start':
        fields.function(
            _estimate_date,
            fnct_inv=_inv_estimate_date,
            type="date",
            help="Best estimate of start date calculated from filled fields."),
        'date_stop':
        fields.function(
            _estimate_date,
            fnct_inv=_inv_estimate_date,
            type="date",
            help="Best estimate of end date calculated from filled fields."),
    }

    _defaults = {'class_id': _default_class}

    _constraints = [
        (check_date_exists,
         _('A desired date of arrival or departure must be set on journey.'),
         ['departure', 'arrival']),
        (check_date_exists_return,
         _('A desired date of arrival or departure must be set on journey for '
           'return.'), ['return_departure', 'return_arrival']),
        (check_date,
         _('Departure date cannot be after arrival date on journey.'),
         ['departure', 'arrival']),
        (check_date_return,
         _('Departure date cannot be after arrival date on journey for '
           'return.'), ['return_departure', 'return_arrival']),
        (check_uom, _('Unit of Measure not specified for Baggage Weight.'), [
            'budget',
            'budget_currency',
        ])
    ]
Beispiel #35
0
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')),
    ('many2many', fields.many2many('export.many2many.other')),
    ('function', fields.function(function_fn, fnct_inv=function_fn_write, type="integer")),
    # related: specialization of fields.function, should work the same way
    # TODO: reference
]

for name, field in models:
    class NewModel(orm.Model):
            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 = {
        'location_id': fields.many2one(
            'stock.location',
            'Location',
            required=True,
            help='The location where you want the valuation (this will '
                 'include all the child locations.'),
        'to_date': fields.datetime(
            'Date',
            help='Date at which the analysis need to be done.'),
    }
    _defaults = {
        'location_id': _default_location,
    }

    def _get_product_qty(self, cr, uid, context=None):
        """Return all product ids that have a qty at the given location for
        the given date in the context. Use SQL for performance here.
        """
        if context is None:
            context = {}
        location_id = context.get('location')
        location_obj = self.pool.get('stock.location')
        child_location_ids = location_obj.search(cr, uid,