Beispiel #1
0
    def _procure_calculation_orderpoint(self):
        with api.Environment.manage():
            # As this function is in a new thread, I need to open a new cursor, because the old one may be closed
            new_cr = self.pool.cursor()
            self = self.with_env(self.env(cr=new_cr))
            scheduler_cron = self.sudo().env.ref(
                'stock.ir_cron_scheduler_action')
            # Avoid to run the scheduler multiple times in the same time
            try:
                with tools.mute_logger('swerp.sql_db'):
                    self._cr.execute(
                        "SELECT id FROM ir_cron WHERE id = %s FOR UPDATE NOWAIT",
                        (scheduler_cron.id, ))
            except Exception:
                _logger.info(
                    'Attempt to run procurement scheduler aborted, as already running'
                )
                self._cr.rollback()
                self._cr.close()
                return {}

            for company in self.env.user.company_ids:
                self.env['procurement.group'].run_scheduler(
                    use_new_cursor=self._cr.dbname, company_id=company.id)
            new_cr.close()
            return {}
Beispiel #2
0
 def test_sale_transaction_mismatch(self):
     """Test that a transaction for the incorrect amount does not validate the SO."""
     # modify order total
     self.order.order_line[0].price_unit = 200.0
     self.transaction._set_transaction_done()
     with mute_logger('swerp.addons.sale.models.payment'):
         self.transaction._post_process_after_done()
     self.assertEqual(self.order.state, 'draft', 'a transaction for an incorrect amount should not validate a quote')
Beispiel #3
0
    def test_00_crossdock(self):

        # Create a supplier
        supplier_crossdock = self.env['res.partner'].create(
            {'name': "Crossdocking supplier"})

        # I first create a warehouse with pick-pack-ship and reception in 2 steps
        wh_f = Form(self.env['stock.warehouse'])
        wh_f.name = 'WareHouse PickPackShip'
        wh_f.code = 'whpps'
        wh_f.reception_steps = 'two_steps'
        wh_f.delivery_steps = 'pick_pack_ship'
        wh_pps = wh_f.save()

        # Check that cross-dock route is active
        self.assertTrue(
            wh_pps.crossdock_route_id.active,
            "Crossdock route should be active when reception_steps is not in 'single_step'"
        )

        p_f = Form(self.env['product.template'])
        p_f.name = 'PCE'
        p_f.type = 'product'
        p_f.categ_id = self.env.ref('product.product_category_1')
        p_f.list_price = 100.0
        p_f.standard_price = 70.0
        with p_f.seller_ids.new() as seller:
            seller.name = supplier_crossdock
        p_f.route_ids.add(wh_pps.crossdock_route_id)
        cross_shop_product = p_f.save()

        # Create a sales order with a line of 100 PCE incoming shipment with route_id crossdock shipping
        so_form = Form(self.env['sale.order'])
        so_form.partner_id = self.env.ref('base.res_partner_4')
        so_form.warehouse_id = wh_pps

        with mute_logger('swerp.tests.common.onchange'):
            # otherwise complains that there's not enough inventory and
            # apparently that's normal according to @jco and @sle
            with so_form.order_line.new() as line:
                line.product_id = cross_shop_product.product_variant_ids
                line.product_uom_qty = 100.0
            sale_order_crossdock = so_form.save()

        # Confirm sales order
        sale_order_crossdock.action_confirm()

        # Run the scheduler
        self.env['procurement.group'].run_scheduler()

        # Check a quotation was created for the created supplier and confirm it
        po = self.env['purchase.order'].search([('partner_id', '=',
                                                 supplier_crossdock.id),
                                                ('state', '=', 'draft')])
        self.assertTrue(po, "an RFQ should have been created by the scheduler")
        po.button_confirm()
Beispiel #4
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('swerp.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()
Beispiel #5
0
    def test_sale_mrp(self):
        warehouse0 = self.env.ref('stock.warehouse0')
        # In order to test the sale_mrp module in OpenERP, I start by creating a new product 'Slider Mobile'
        # I define product category Mobile Products Sellable.

        with mute_logger('swerp.tests.common.onchange'):
            # Suppress warning on "Changing your cost method" when creating a
            # product category
            pc = Form(self.env['product.category'])
        pc.name = 'Mobile Products Sellable'
        product_category_allproductssellable0 = pc.save()

        uom_unit = self.env.ref('uom.product_uom_unit')

        self.assertIn("seller_ids", self.env['product.template'].fields_get())

        # I define product for Slider Mobile.
        product = Form(self.env['product.template'])

        product.categ_id = product_category_allproductssellable0
        product.list_price = 200.0
        product.name = 'Slider Mobile'
        product.standard_price = 189.0
        product.type = 'product'
        product.uom_id = uom_unit
        product.uom_po_id = uom_unit
        product.route_ids.clear()
        product.route_ids.add(warehouse0.manufacture_pull_id.route_id)
        product.route_ids.add(warehouse0.mto_pull_id.route_id)
        product_template_slidermobile0 = product.save()

        with Form(self.env['mrp.bom']) as bom:
            bom.product_tmpl_id = product_template_slidermobile0

        # I create a sale order for product Slider mobile
        so_form = Form(self.env['sale.order'])
        so_form.partner_id = self.env.ref('base.res_partner_4')
        with so_form.order_line.new() as line:
            line.product_id = product_template_slidermobile0.product_variant_ids
            line.price_unit = 200
            line.product_uom_qty = 500.0
            line.customer_lead = 7.0
        sale_order_so0 = so_form.save()

        # I confirm the sale order
        sale_order_so0.action_confirm()

        # I verify that a manufacturing order has been generated, and that its name and reference are correct
        mo = self.env['mrp.production'].search(
            [('origin', 'like', sale_order_so0.name)], limit=1)
        self.assertTrue(mo, 'Manufacturing order has not been generated')
Beispiel #6
0
 def send_email(self, message, *args, **kwargs):
     with this.registry.cursor() as cr, mute_logger('swerp.sql_db'):
         try:
             # try ro aquire lock (no wait) on notification (should fail)
             cr.execute("SELECT email_status FROM mail_message_res_partner_needaction_rel WHERE id = %s FOR UPDATE NOWAIT", [notif.id])
         except psycopg2.OperationalError:
             # record already locked by send, all good
             bounce_deferred.append(True)
         else:
             # this should trigger psycopg2.extensions.TransactionRollbackError in send().
             # Only here to simulate the initial use case
             # If the record is lock, this line would create a deadlock since we are in the same thread
             # In practice, the update will wait the end of the send() transaction and set the notif as bounce, as expeced
             cr.execute("UPDATE mail_message_res_partner_needaction_rel SET email_status='bounce' WHERE id = %s", [notif.id])
     return message['Message-Id']
Beispiel #7
0
 def _update(self, inactivity_period):
     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
         self.create(values)
     else:  # update the last_presence if necessary, and write values
         if presence.last_presence < last_presence:
             values['last_presence'] = last_presence
         # Hide transaction serialization errors, which can be ignored, the presence update is not essential
         with tools.mute_logger('swerp.sql_db'):
             presence.write(values)
Beispiel #8
0
 def test_105_duplicated_translation(self):
     """ Test synchronizing translations with duplicated source """
     # create a category with a French translation
     padawans = self.env['res.partner.category'].create({'name': 'Padawan'})
     self.env['ir.translation'].create({
         'type': 'model',
         'name': 'res.partner.category,name',
         'module': 'base',
         'lang': 'fr_FR',
         'res_id': padawans.id,
         'value': 'Apprenti',
         'state': 'translated',
     })
     # change name and insert a duplicate manually
     padawans.write({'name': 'Padawans'})
     with self.assertRaises(IntegrityError), mute_logger('swerp.sql_db'):
         with self.env.cr.savepoint():
             self.env['ir.translation'].create({
                 'type': 'model',
                 'name': 'res.partner.category,name',
                 'module': 'base',
                 'lang': 'fr_FR',
                 'res_id': padawans.id,
                 'value': 'Apprentis',
                 'state': 'translated',
             })
     self.env['ir.translation'].translate_fields('res.partner.category',
                                                 padawans.id, 'name')
     translations = self.env['ir.translation'].search([
         ('res_id', '=', padawans.id),
         ('name', '=', 'res.partner.category,name')
     ])
     self.assertEqual(
         len(translations), 1,
         "Translations were not duplicated after `translate_fields` call")
     self.assertEqual(translations.value, "Apprenti",
                      "The first translation must stay")
Beispiel #9
0
    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': 470000,
            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-1'
            },
            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.0,
            'acquirer_id':
            self.stripe.id,
            'currency_id':
            self.currency_euro.id,
            'reference':
            'SO100-1',
            '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')
        stripe_post_data['metadata']['reference'] = u'SO100-2'
        # reset tx
        tx = self.env['payment.transaction'].create({
            'amount':
            4700.0,
            'acquirer_id':
            self.stripe.id,
            'currency_id':
            self.currency_euro.id,
            'reference':
            'SO100-2',
            'partner_name':
            'Norbert Buyer',
            'partner_country_id':
            self.country_france.id
        })
        # 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('swerp.addons.payment_stripe.models.payment'):
            with mute_logger('swerp.addons.payment_stripe_sca.models.payment'):
                tx.form_feedback(stripe_post_data, 'stripe')
        # check state
        self.assertEqual(
            tx.state, 'cancel',
            'Stipe: erroneous validation did not put tx into error state')
Beispiel #10
0
 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('swerp.sql_db'):
         field2.name = field1.name
    def test_create_from_ui(self):
        """
        Simulation of sales coming from the interface, even after closing the session
        """

        # 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 = self.compute_tax(self.led_lamp, 0.9)
        carrot_order = {'data':
          {'amount_paid': untax + atax,
           'amount_return': 0,
           'amount_tax': atax,
           'amount_total': untax + atax,
           'creation_date': fields.Datetime.to_string(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.led_lamp.id,
              'price_subtotal': 0.9,
              'price_subtotal_incl': 1.04,
              'qty': 1,
              'tax_ids': [(6, 0, self.led_lamp.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 = self.compute_tax(self.whiteboard_pen, 1.2)
        zucchini_order = {'data':
          {'amount_paid': untax + atax,
           'amount_return': 0,
           'amount_tax': atax,
           'amount_total': untax + atax,
           'creation_date': fields.Datetime.to_string(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.whiteboard_pen.id,
              'price_subtotal': 1.2,
              'price_subtotal_incl': 1.38,
              'qty': 1,
              'tax_ids': [(6, 0, self.whiteboard_pen.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 = self.compute_tax(self.newspaper_rack, 1.28)
        newspaper_rack_order = {'data':
          {'amount_paid': untax + atax,
           'amount_return': 0,
           'amount_tax': atax,
           'amount_total': untax + atax,
           'creation_date': fields.Datetime.to_string(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.newspaper_rack.id,
              'price_subtotal': 1.28,
              'price_subtotal_incl': 1.47,
              'qty': 1,
              'tax_ids': [[6, False, self.newspaper_rack.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('swerp.addons.point_of_sale.models.pos_order'):
            self.PosOrder.create_from_ui([zucchini_order, newspaper_rack_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")
Beispiel #12
0
    def test_proc_rule(self):
        # Create a product route containing a stock rule that will
        # generate a move from Stock for every procurement created in Output
        product_route = self.env['stock.location.route'].create({
            'name':
            'Stock -> output route',
            'product_selectable':
            True,
            'rule_ids': [(0, 0, {
                'name':
                'Stock -> output rule',
                'action':
                'pull',
                'picking_type_id':
                self.ref('stock.picking_type_internal'),
                'location_src_id':
                self.ref('stock.stock_location_stock'),
                'location_id':
                self.ref('stock.stock_location_output'),
            })],
        })

        # Set this route on `product.product_product_3`
        self.env.ref('product.product_product_3').write(
            {'route_ids': [(4, product_route.id)]})

        # Create Delivery Order of 10 `product.product_product_3` from Output -> Customer
        product = self.env.ref('product.product_product_3')
        vals = {
            'name':
            'Delivery order for procurement',
            'partner_id':
            self.ref('base.res_partner_2'),
            'picking_type_id':
            self.ref('stock.picking_type_out'),
            'location_id':
            self.ref('stock.stock_location_output'),
            'location_dest_id':
            self.ref('stock.stock_location_customers'),
            'move_lines': [(0, 0, {
                'name': '/',
                'product_id': product.id,
                'product_uom': product.uom_id.id,
                'product_uom_qty': 10.00,
                'procure_method': 'make_to_order',
            })],
        }
        pick_output = self.env['stock.picking'].create(vals)
        pick_output.move_lines.onchange_product_id()

        # Confirm delivery order.
        pick_output.action_confirm()

        # I run the scheduler.
        # Note: If purchase if already installed, the method _run_buy will be called due
        # to the purchase demo data. As we update the stock module to run this test, the
        # method won't be an attribute of stock.procurement at this moment. For that reason
        # we mute the logger when running the scheduler.
        with mute_logger('swerp.addons.stock.models.procurement'):
            self.env['procurement.group'].run_scheduler()

        # Check that a picking was created from stock to output.
        moves = self.env['stock.move'].search([
            ('product_id', '=', self.ref('product.product_product_3')),
            ('location_id', '=', self.ref('stock.stock_location_stock')),
            ('location_dest_id', '=', self.ref('stock.stock_location_output')),
            ('move_dest_ids', 'in', [pick_output.move_lines[0].id])
        ])
        self.assertEqual(
            len(moves.ids), 1,
            "It should have created a picking from Stock to Output with the original picking as destination"
        )
Beispiel #13
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('swerp.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),))
Beispiel #14
0
    def test_00_dropship(self):

        # Create a vendor
        supplier_dropship = self.env['res.partner'].create(
            {'name': 'Vendor of Dropshipping test'})

        # Create new product without any routes
        drop_shop_product = self.env['product.product'].create({
            'name':
            "Pen drive",
            'type':
            "product",
            'categ_id':
            self.env.ref('product.product_category_1').id,
            'lst_price':
            100.0,
            'standard_price':
            0.0,
            'uom_id':
            self.env.ref('uom.product_uom_unit').id,
            'uom_po_id':
            self.env.ref('uom.product_uom_unit').id,
            'seller_ids': [(0, 0, {
                'delay': 1,
                'name': supplier_dropship.id,
                'min_qty': 2.0
            })]
        })

        # Create a sales order with a line of 200 PCE incoming shipment, with route_id drop shipping
        so_form = Form(self.env['sale.order'])
        so_form.partner_id = self.env.ref('base.res_partner_2')
        so_form.payment_term_id = self.env.ref('account.account_payment_term')
        with mute_logger('swerp.tests.common.onchange'):
            # otherwise complains that there's not enough inventory and
            # apparently that's normal according to @jco and @sle
            with so_form.order_line.new() as line:
                line.product_id = drop_shop_product
                line.product_uom_qty = 200
                line.price_unit = 1.00
                line.route_id = self.env.ref(
                    'stock_dropshipping.route_drop_shipping')
        sale_order_drp_shpng = so_form.save()

        # Confirm sales order
        sale_order_drp_shpng.action_confirm()

        # Check the sales order created a procurement group which has a procurement of 200 pieces
        self.assertTrue(sale_order_drp_shpng.procurement_group_id,
                        'SO should have procurement group')

        # Check a quotation was created to a certain vendor and confirm so it becomes a confirmed purchase order
        purchase = self.env['purchase.order'].search([('partner_id', '=',
                                                       supplier_dropship.id)])
        self.assertTrue(purchase,
                        "an RFQ should have been created by the scheduler")
        purchase.button_confirm()
        self.assertEquals(purchase.state, 'purchase',
                          'Purchase order should be in the approved state')
        self.assertEquals(len(purchase.ids), 1, 'There should be one picking')

        # Send the 200 pieces
        purchase.picking_ids.move_lines.quantity_done = purchase.picking_ids.move_lines.product_qty
        purchase.picking_ids.button_validate()

        # Check one move line was created in Customers location with 200 pieces
        move_line = self.env['stock.move.line'].search([
            ('location_dest_id', '=',
             self.env.ref('stock.stock_location_customers').id),
            ('product_id', '=', drop_shop_product.id)
        ])
        self.assertEquals(len(move_line.ids), 1,
                          'There should be exactly one move line')