コード例 #1
0
 def update(self, inactivity_period):
     """ Updates the last_poll and last_presence of the current user
         :param inactivity_period: duration in milliseconds
     """
     presence = self.search([('user_id', '=', self._uid)], limit=1)
     # compute last_presence timestamp
     last_presence = datetime.datetime.now() - datetime.timedelta(
         milliseconds=inactivity_period)
     values = {
         'last_poll': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
     }
     # update the presence or a create a new one
     if not presence:  # create a new presence for the user
         values['user_id'] = self._uid
         values['last_presence'] = last_presence.strftime(
             DEFAULT_SERVER_DATETIME_FORMAT)
         self.create(values)
     else:  # update the last_presence if necessary, and write values
         if datetime.datetime.strptime(
                 presence.last_presence,
                 DEFAULT_SERVER_DATETIME_FORMAT) < last_presence:
             values['last_presence'] = last_presence.strftime(
                 DEFAULT_SERVER_DATETIME_FORMAT)
         # Hide transaction serialization errors, which can be ignored, the presence update is not essential
         with tools.mute_logger('actpy.sql_db'):
             presence.write(values)
     # avoid TransactionRollbackError
     self.env.cr.commit()  # TODO : check if still necessary
コード例 #2
0
    def create_variant_ids(self):
        Product = self.env["product.product"]
        AttributeValues = self.env['product.attribute.value']
        for tmpl_id in self.with_context(active_test=False):
            # adding an attribute with only one value should not recreate product
            # write this attribute on every product to make sure we don't lose them
            variant_alone = tmpl_id.attribute_line_ids.filtered(lambda line: line.attribute_id.create_variant and len(line.value_ids) == 1).mapped('value_ids')
            for value_id in variant_alone:
                updated_products = tmpl_id.product_variant_ids.filtered(lambda product: value_id.attribute_id not in product.mapped('attribute_value_ids.attribute_id'))
                updated_products.write({'attribute_value_ids': [(4, value_id.id)]})

            # iterator of n-uple of product.attribute.value *ids*
            variant_matrix = [
                AttributeValues.browse(value_ids)
                for value_ids in itertools.product(*(line.value_ids.ids for line in tmpl_id.attribute_line_ids if line.value_ids[:1].attribute_id.create_variant))
            ]

            # get the value (id) sets of existing variants
            existing_variants = {frozenset(variant.attribute_value_ids.filtered(lambda r: r.attribute_id.create_variant).ids) for variant in tmpl_id.product_variant_ids}
            # -> for each value set, create a recordset of values to create a
            #    variant for if the value set isn't already a variant
            to_create_variants = [
                value_ids
                for value_ids in variant_matrix
                if set(value_ids.ids) not in existing_variants
            ]

            # check product
            variants_to_activate = self.env['product.product']
            variants_to_unlink = self.env['product.product']
            for product_id in tmpl_id.product_variant_ids:
                if not product_id.active and product_id.attribute_value_ids.filtered(lambda r: r.attribute_id.create_variant) in variant_matrix:
                    variants_to_activate |= product_id
                elif product_id.attribute_value_ids.filtered(lambda r: r.attribute_id.create_variant) not in variant_matrix:
                    variants_to_unlink |= product_id
            if variants_to_activate:
                variants_to_activate.write({'active': True})

            # create new product
            for variant_ids in to_create_variants:
                new_variant = Product.create({
                    'product_tmpl_id': tmpl_id.id,
                    'attribute_value_ids': [(6, 0, variant_ids.ids)]
                })

            # unlink or inactive product
            for variant in variants_to_unlink:
                try:
                    with self._cr.savepoint(), tools.mute_logger('actpy.sql_db'):
                        variant.unlink()
                # We catch all kind of exception to be sure that the operation doesn't fail.
                except (psycopg2.Error, except_orm):
                    variant.write({'active': False})
                    pass
        return True
コード例 #3
0
 def update_records(model, src, field_model='model', field_id='res_id'):
     Model = self.env[model] if model in self.env else None
     if Model is None:
         return
     records = Model.sudo().search([(field_model, '=', 'res.partner'),
                                    (field_id, '=', src.id)])
     try:
         with mute_logger('actpy.sql_db'), self._cr.savepoint():
             return records.sudo().write({field_id: dst_partner.id})
     except psycopg2.Error:
         # updating fails, most likely due to a violated unique constraint
         # keeping record with nonexistent partner_id is useless, better delete it
         return records.sudo().unlink()
コード例 #4
0
ファイル: test_ir_actions.py プロジェクト: yasr3mr96/actpy
 def test_rename_unique(self):
     """ one cannot create two fields with the same name on a given model """
     field1 = self.create_field('x_foo')
     field2 = self.create_field('x_bar')
     with self.assertRaises(IntegrityError), mute_logger('actpy.sql_db'):
         field2.name = field1.name
コード例 #5
0
    def test_create_from_ui(self):
        """
        Simulation of sales coming from the interface, even after closing the session
        """
        FROMPRODUCT = object()

        def compute_tax(product, price, taxes=FROMPRODUCT, qty=1):
            if taxes is FROMPRODUCT:
                taxes = product.taxes_id
            currency = self.pos_config.pricelist_id.currency_id
            taxes = taxes.compute_all(price, currency, qty,
                                      product=product)['taxes']
            untax = price * qty
            return untax, sum(tax.get('amount', 0.0) for tax in taxes)

        # I click on create a new session button
        self.pos_config.open_session_cb()

        current_session = self.pos_config.current_session_id
        num_starting_orders = len(current_session.order_ids)

        untax, atax = compute_tax(self.carotte, 0.9)
        carrot_order = {
            'data': {
                'amount_paid':
                untax + atax,
                'amount_return':
                0,
                'amount_tax':
                atax,
                'amount_total':
                untax + atax,
                'creation_date':
                fields.Datetime.now(),
                'fiscal_position_id':
                False,
                'pricelist_id':
                self.pos_config.available_pricelist_ids[0].id,
                'lines': [[
                    0, 0, {
                        'discount': 0,
                        'id': 42,
                        'pack_lot_ids': [],
                        'price_unit': 0.9,
                        'product_id': self.carotte.id,
                        'qty': 1,
                        'tax_ids': [(6, 0, self.carotte.taxes_id.ids)]
                    }
                ]],
                'name':
                'Order 00042-003-0014',
                'partner_id':
                False,
                'pos_session_id':
                current_session.id,
                'sequence_number':
                2,
                'statement_ids': [[
                    0, 0, {
                        'account_id':
                        self.env.user.partner_id.
                        property_account_receivable_id.id,
                        'amount':
                        untax + atax,
                        'journal_id':
                        self.pos_config.journal_ids[0].id,
                        'name':
                        fields.Datetime.now(),
                        'statement_id':
                        current_session.statement_ids[0].id
                    }
                ]],
                'uid':
                '00042-003-0014',
                'user_id':
                self.env.uid
            },
            'id': '00042-003-0014',
            'to_invoice': False
        }

        untax, atax = compute_tax(self.courgette, 1.2)
        zucchini_order = {
            'data': {
                'amount_paid':
                untax + atax,
                'amount_return':
                0,
                'amount_tax':
                atax,
                'amount_total':
                untax + atax,
                'creation_date':
                fields.Datetime.now(),
                'fiscal_position_id':
                False,
                'pricelist_id':
                self.pos_config.available_pricelist_ids[0].id,
                'lines': [[
                    0, 0, {
                        'discount': 0,
                        'id': 3,
                        'pack_lot_ids': [],
                        'price_unit': 1.2,
                        'product_id': self.courgette.id,
                        'qty': 1,
                        'tax_ids': [(6, 0, self.courgette.taxes_id.ids)]
                    }
                ]],
                'name':
                'Order 00043-003-0014',
                'partner_id':
                False,
                'pos_session_id':
                current_session.id,
                'sequence_number':
                self.pos_config.journal_id.id,
                'statement_ids': [[
                    0, 0, {
                        'account_id':
                        self.env.user.partner_id.
                        property_account_receivable_id.id,
                        'amount':
                        untax + atax,
                        'journal_id':
                        self.pos_config.journal_ids[0].id,
                        'name':
                        fields.Datetime.now(),
                        'statement_id':
                        current_session.statement_ids[0].id
                    }
                ]],
                'uid':
                '00043-003-0014',
                'user_id':
                self.env.uid
            },
            'id': '00043-003-0014',
            'to_invoice': False
        }

        untax, atax = compute_tax(self.onions, 1.28)
        onions_order = {
            'data': {
                'amount_paid':
                untax + atax,
                'amount_return':
                0,
                'amount_tax':
                atax,
                'amount_total':
                untax + atax,
                'creation_date':
                fields.Datetime.now(),
                'fiscal_position_id':
                False,
                'pricelist_id':
                self.pos_config.available_pricelist_ids[0].id,
                'lines': [[
                    0, 0, {
                        'discount': 0,
                        'id': 3,
                        'pack_lot_ids': [],
                        'price_unit': 1.28,
                        'product_id': self.onions.id,
                        'qty': 1,
                        'tax_ids': [[6, False, self.onions.taxes_id.ids]]
                    }
                ]],
                'name':
                'Order 00044-003-0014',
                'partner_id':
                False,
                'pos_session_id':
                current_session.id,
                'sequence_number':
                self.pos_config.journal_id.id,
                'statement_ids': [[
                    0, 0, {
                        'account_id':
                        self.env.user.partner_id.
                        property_account_receivable_id.id,
                        'amount':
                        untax + atax,
                        'journal_id':
                        self.pos_config.journal_ids[0].id,
                        'name':
                        fields.Datetime.now(),
                        'statement_id':
                        current_session.statement_ids[0].id
                    }
                ]],
                'uid':
                '00044-003-0014',
                'user_id':
                self.env.uid
            },
            'id': '00044-003-0014',
            'to_invoice': False
        }

        # I create an order on an open session
        self.PosOrder.create_from_ui([carrot_order])
        self.assertEqual(num_starting_orders + 1,
                         len(current_session.order_ids),
                         "Submitted order not encoded")

        # I resubmit the same order
        self.PosOrder.create_from_ui([carrot_order])
        self.assertEqual(num_starting_orders + 1,
                         len(current_session.order_ids),
                         "Resubmitted order was not skipped")

        # I close the session
        current_session.action_pos_session_closing_control()
        self.assertEqual(current_session.state, 'closed',
                         "Session was not properly closed")
        self.assertFalse(self.pos_config.current_session_id,
                         "Current session not properly recomputed")

        # I keep selling after the session is closed
        with mute_logger('actpy.addons.point_of_sale.models.pos_order'):
            self.PosOrder.create_from_ui([zucchini_order, onions_order])
        rescue_session = self.PosSession.search([('config_id', '=',
                                                  self.pos_config.id),
                                                 ('state', '=', 'opened'),
                                                 ('rescue', '=', True)])
        self.assertEqual(
            len(rescue_session), 1,
            "One (and only one) rescue session should be created for orphan orders"
        )
        self.assertIn("(RESCUE FOR %s)" % current_session.name,
                      rescue_session.name,
                      "Rescue session is not linked to the previous one")
        self.assertEqual(len(rescue_session.order_ids), 2,
                         "Rescue session does not contain both orders")

        # I close the rescue session
        rescue_session.action_pos_session_closing_control()
        self.assertEqual(rescue_session.state, 'closed',
                         "Rescue session was not properly closed")
コード例 #6
0
ファイル: test_stripe.py プロジェクト: yasr3mr96/actpy
    def test_30_stripe_form_management(self):
        self.assertEqual(self.stripe.environment, 'test', 'test without test environment')

        # typical data posted by Stripe after client has successfully paid
        stripe_post_data = {
            u'amount': 4700,
            u'amount_refunded': 0,
            u'application_fee': None,
            u'balance_transaction': u'txn_172xfnGMfVJxozLwssrsQZyT',
            u'captured': True,
            u'created': 1446529775,
            u'currency': u'eur',
            u'customer': None,
            u'description': None,
            u'destination': None,
            u'dispute': None,
            u'failure_code': None,
            u'failure_message': None,
            u'fraud_details': {},
            u'id': u'ch_172xfnGMfVJxozLwEjSfpfxD',
            u'invoice': None,
            u'livemode': False,
            u'metadata': {u'reference': u'SO100'},
            u'object': u'charge',
            u'paid': True,
            u'receipt_email': None,
            u'receipt_number': None,
            u'refunded': False,
            u'refunds': {u'data': [],
                         u'has_more': False,
                         u'object': u'list',
                         u'total_count': 0,
                         u'url': u'/v1/charges/ch_172xfnGMfVJxozLwEjSfpfxD/refunds'},
            u'shipping': None,
            u'source': {u'address_city': None,
                        u'address_country': None,
                        u'address_line1': None,
                        u'address_line1_check': None,
                        u'address_line2': None,
                        u'address_state': None,
                        u'address_zip': None,
                        u'address_zip_check': None,
                        u'brand': u'Visa',
                        u'country': u'US',
                        u'customer': None,
                        u'cvc_check': u'pass',
                        u'dynamic_last4': None,
                        u'exp_month': 2,
                        u'exp_year': 2022,
                        u'fingerprint': u'9tJA9bUEuvEb3Ell',
                        u'funding': u'credit',
                        u'id': u'card_172xfjGMfVJxozLw1QO6gYNM',
                        u'last4': u'4242',
                        u'metadata': {},
                        u'name': u'*****@*****.**',
                        u'object': u'card',
                        u'tokenization_method': None},
            u'statement_descriptor': None,
            u'status': u'succeeded'}

        tx = self.env['payment.transaction'].create({
            'amount': 4700,
            'acquirer_id': self.stripe.id,
            'currency_id': self.currency_euro.id,
            'reference': 'SO100',
            'partner_name': 'Norbert Buyer',
            'partner_country_id': self.country_france.id})

        # validate it
        tx.form_feedback(stripe_post_data, 'stripe')
        self.assertEqual(tx.state, 'done', 'Stripe: validation did not put tx into done state')
        self.assertEqual(tx.acquirer_reference, stripe_post_data.get('id'), 'Stripe: validation did not update tx id')
        # reset tx
        tx.write({'state': 'draft', 'date_validate': False, 'acquirer_reference': False})
        # simulate an error
        stripe_post_data['status'] = 'error'
        stripe_post_data.update({u'error': {u'message': u"Your card's expiration year is invalid.", u'code': u'invalid_expiry_year', u'type': u'card_error', u'param': u'exp_year'}})
        with mute_logger('actpy.addons.payment_stripe.models.payment'):
            tx.form_feedback(stripe_post_data, 'stripe')
        # check state
        self.assertEqual(tx.state, 'error', 'Stipe: erroneous validation did not put tx into error state')
コード例 #7
0
    def _update_foreign_keys(self, src_partners, dst_partner):
        """ Update all foreign key from the src_partner to dst_partner. All many2one fields will be updated.
            :param src_partners : merge source res.partner recordset (does not include destination one)
            :param dst_partner : record of destination res.partner
        """
        _logger.debug(
            '_update_foreign_keys for dst_partner: %s for src_partners: %s',
            dst_partner.id, str(src_partners.ids))

        # find the many2one relation to a partner
        Partner = self.env['res.partner']
        relations = self._get_fk_on('res_partner')

        for table, column in relations:
            if 'base_partner_merge_' in table:  # ignore two tables
                continue

            # get list of columns of current table (exept the current fk column)
            query = "SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%s'" % (
                table)
            self._cr.execute(query, ())
            columns = []
            for data in self._cr.fetchall():
                if data[0] != column:
                    columns.append(data[0])

            # do the update for the current table/column in SQL
            query_dic = {
                'table': table,
                'column': column,
                'value': columns[0],
            }
            if len(columns) <= 1:
                # unique key treated
                query = """
                    UPDATE "%(table)s" as ___tu
                    SET %(column)s = %%s
                    WHERE
                        %(column)s = %%s AND
                        NOT EXISTS (
                            SELECT 1
                            FROM "%(table)s" as ___tw
                            WHERE
                                %(column)s = %%s AND
                                ___tu.%(value)s = ___tw.%(value)s
                        )""" % query_dic
                for partner in src_partners:
                    self._cr.execute(
                        query, (dst_partner.id, partner.id, dst_partner.id))
            else:
                try:
                    with mute_logger('actpy.sql_db'), self._cr.savepoint():
                        query = 'UPDATE "%(table)s" SET %(column)s = %%s WHERE %(column)s IN %%s' % query_dic
                        self._cr.execute(query, (
                            dst_partner.id,
                            tuple(src_partners.ids),
                        ))

                        # handle the recursivity with parent relation
                        if column == Partner._parent_name and table == 'res_partner':
                            query = """
                                WITH RECURSIVE cycle(id, parent_id) AS (
                                        SELECT id, parent_id FROM res_partner
                                    UNION
                                        SELECT  cycle.id, res_partner.parent_id
                                        FROM    res_partner, cycle
                                        WHERE   res_partner.id = cycle.parent_id AND
                                                cycle.id != cycle.parent_id
                                )
                                SELECT id FROM cycle WHERE id = parent_id AND id = %s
                            """
                            self._cr.execute(query, (dst_partner.id, ))
                            # NOTE JEM : shouldn't we fetch the data ?
                except psycopg2.Error:
                    # updating fails, most likely due to a violated unique constraint
                    # keeping record with nonexistent partner_id is useless, better delete it
                    query = 'DELETE FROM "%(table)s" WHERE "%(column)s" IN %%s' % query_dic
                    self._cr.execute(query, (tuple(src_partners.ids), ))