示例#1
0
    def testTimestamp(self):
        # Create person
        before = _query_server_time(self.store)
        person = Person(name=u'dummy', store=self.store)
        created = _query_server_time(self.store)

        self.store.commit()

        # Now modify the person
        first_te = person.te.te_time
        person.name = NAME
        self.store.commit()

        # te_time should have changed
        self.assertNotEqual(first_te, person.te.te_time)

        updated = _query_server_time(self.store)

        dates = [
            (u'before create', before),
            (u'create', first_te),
            (u'after create', created),
            (u'modifiy', person.te.te_time),
            (u'after modify', updated),
        ]
        for i in range(len(dates) - 1):
            before_name, before = dates[i]
            after_name, after = dates[i + 1]
            before_decimal = Decimal(before.strftime(u'%s.%f'))
            after_decimal = Decimal(after.strftime(u'%s.%f'))
            if before_decimal > after_decimal:
                raise AssertionError(
                    u"'%s' (%s) was expected to be before '%s' (%s)" % (
                    before_name, before, after_name, after))
示例#2
0
    def test_timestamp(self):
        # Create person
        before = _query_server_time(self.store)
        person = Person(name=u'dummy', store=self.store)
        created = _query_server_time(self.store)

        self.store.commit()

        # Now modify the person
        first_te = person.te.te_time
        person.name = u'dummy transaction test'
        self.store.commit()

        # te_time should have changed
        self.assertNotEqual(first_te, person.te.te_time)

        updated = _query_server_time(self.store)

        dates = [
            (u'before create', before),
            (u'create', first_te),
            (u'after create', created),
            (u'modifiy', person.te.te_time),
            (u'after modify', updated),
        ]
        for i in range(len(dates) - 1):
            before_name, before = dates[i]
            after_name, after = dates[i + 1]
            before_decimal = Decimal(before.strftime(u'%s.%f'))
            after_decimal = Decimal(after.strftime(u'%s.%f'))
            if before_decimal > after_decimal:
                fmt = u"'%s' (%s) was expected to be before '%s' (%s)"
                raise AssertionError(fmt %
                                     (before_name, before, after_name, after))
示例#3
0
    def test_get_by_phone_number(self):
        person = self.create_person()

        self.assertTrue(Person.get_by_phone_number(
            self.store, u'1138').is_empty())
        person.phone_number = u'1138'
        self.assertFalse(Person.get_by_phone_number(
            self.store, u'1138').is_empty())
        person.phone_number = u'0'
        self.assertTrue(Person.get_by_phone_number(
            self.store, u'1138').is_empty())
        person.mobile_number = u'1138'
        self.assertFalse(Person.get_by_phone_number(
            self.store, u'1138').is_empty())
示例#4
0
    def test_get_by_phone_number(self):
        person = self.create_person()

        self.assertTrue(
            Person.get_by_phone_number(self.store, u'1138').is_empty())
        person.phone_number = u'1138'
        self.assertFalse(
            Person.get_by_phone_number(self.store, u'1138').is_empty())
        person.phone_number = u'0'
        self.assertTrue(
            Person.get_by_phone_number(self.store, u'1138').is_empty())
        person.mobile_number = u'1138'
        self.assertFalse(
            Person.get_by_phone_number(self.store, u'1138').is_empty())
示例#5
0
 def test_default_receiving_cfop(self):
     branch = self.create_branch()
     param = self.sparam.get_object(self.store, 'DEFAULT_RECEIVING_CFOP')
     person = Person(name=u'Craudinho', store=self.store)
     Individual(person=person, store=self.store)
     profile = UserProfile(name=u'profile', store=self.store)
     responsible = LoginUser(person=person,
                             store=self.store,
                             password=u'asdfgh',
                             profile=profile,
                             username=u'craudio')
     receiving_order = ReceivingOrder(responsible=responsible,
                                      branch=branch,
                                      store=self.store,
                                      invoice_number=876,
                                      supplier=None)
     param2 = self.sparam.get_object(self.store, 'DEFAULT_SALES_CFOP')
     receiving_order2 = ReceivingOrder(responsible=responsible,
                                       cfop=param2,
                                       branch=branch,
                                       store=self.store,
                                       invoice_number=1231,
                                       supplier=None)
     self.assertEqual(param, receiving_order.cfop)
     self.failIfEqual(param, receiving_order2.cfop)
示例#6
0
 def create_supplier(self, name=u'Supplier', fancy_name=u'Company Name'):
     from stoqlib.domain.person import Company, Person, Supplier
     person = Person(name=name, store=self.store)
     Company(person=person, fancy_name=fancy_name,
             cnpj=u'90.117.749/7654-80',
             store=self.store)
     return Supplier(person=person, store=self.store)
示例#7
0
    def process_one(self, data, fields, store):
        person = Person(
            store=store,
            name=data.name,
            phone_number=data.phone_number,
            mobile_number=data.mobile_number)

        Individual(person=person,
                   store=store,
                   cpf=data.cpf,
                   rg_number=data.rg)

        ctloc = CityLocation.get_or_create(store=store,
                                           city=data.city,
                                           state=data.state,
                                           country=data.country)
        streetnumber = data.streetnumber and int(data.streetnumber) or None
        Address(
            is_main_address=True,
            person=person,
            city_location=ctloc,
            store=store,
            street=data.street,
            streetnumber=streetnumber,
            district=data.district
        )

        Client(person=person, store=store)
示例#8
0
    def test_remove(self):
        # Total of transaction entries in the begining of the test
        start_te = self.store.find(TransactionEntry).count()

        person = Person(name=u'dummy', store=self.store)
        person_te_id = person.te.id

        # Afte creating a person, there should be one transaction entry more
        total_te = self.store.find(TransactionEntry).count()
        self.assertEqual(total_te, start_te + 1)

        person_te = self.store.find(TransactionEntry, id=person_te_id).one()
        self.assertEqual(person.te.id, person_te.id)

        # Now remove this person, and the transaction entry should be gone
        self.store.remove(person)

        # Total of transaction entries is back to the original
        total_te = self.store.find(TransactionEntry).count()
        self.assertEqual(total_te, start_te)

        # The transaction entry created for the person should be removed from
        # the database
        person_te = self.store.find(TransactionEntry, id=person_te_id).one()
        self.assertEqual(person_te, None)
示例#9
0
    def process_one(self, data, fields, store):
        person = Person(store=store,
                        name=data.name,
                        phone_number=data.phone_number,
                        fax_number=data.fax_number)

        Company(person=person,
                cnpj=data.cnpj,
                state_registry=data.state_registry,
                fancy_name=data.fancy_name,
                store=store)

        ctloc = CityLocation.get_or_create(store=store,
                                           city=data.city,
                                           state=data.state,
                                           country=data.country)
        streetnumber = data.streetnumber and int(data.streetnumber) or None
        Address(is_main_address=True,
                person=person,
                city_location=ctloc,
                store=store,
                street=data.street,
                streetnumber=streetnumber,
                district=data.district,
                postal_code=data.postal_code)

        branch = Branch(person=person, store=store)
        for user in store.find(LoginUser):
            user.add_access_to(branch)
        self.branches.append(branch)
示例#10
0
    def process_one(self, data, fields, store):
        person = Person(store=store,
                        name=data.name,
                        phone_number=data.phone_number,
                        mobile_number=data.mobile_number)

        Company(person=person,
                store=store,
                cnpj=data.cnpj,
                fancy_name=data.name,
                state_registry=data.state_registry)

        ctloc = CityLocation.get_or_create(store=store,
                                           city=data.city,
                                           state=data.state,
                                           country=data.country)
        streetnumber = data.streetnumber and int(data.streetnumber) or None
        Address(is_main_address=True,
                person=person,
                city_location=ctloc,
                store=store,
                street=data.street,
                streetnumber=streetnumber,
                district=data.district)

        Transporter(person=person,
                    open_contract_date=self.parse_date(data.open_contract),
                    freight_percentage=decimal.Decimal(
                        data.freight_percentage),
                    store=store)
示例#11
0
    def testCacheInvalidation(self):
        # First create a new person in an outside transaction
        outside_store = new_store()
        outside_person = Person(name=u'doe', store=outside_store)
        outside_store.commit()

        # Get this person in the default store
        default_store = get_default_store()
        db_person = default_store.find(Person, id=outside_person.id).one()
        self.assertEqual(db_person.name, u'doe')

        # Now, select that same person in an inside store
        inside_store = new_store()
        inside_person = inside_store.fetch(outside_person)

        # Change and commit the changes on this inside store
        inside_person.name = u'john'

        # Flush to make sure the database was updated
        inside_store.flush()

        # Before comminting the other persons should still be 'doe'
        self.assertEqual(db_person.name, u'doe')
        self.assertEqual(outside_person.name, u'doe')

        inside_store.commit()

        # We expect the changes to reflect on the connection
        self.assertEqual(db_person.name, u'john')

        # and also on the outside store
        self.assertEqual(outside_person.name, u'john')

        outside_store.close()
        inside_store.close()
示例#12
0
def test_get_or_create_by_document_with_existing_person(
        store, example_creator):
    person = example_creator.create_person()
    individual = example_creator.create_individual(person=person)
    individual.cpf = '437.433.508-07'

    assert Person.get_or_create_by_document(store, '437.433.508-07') is person
示例#13
0
def _provide_current_station(station_name=None, branch_name=None):
    if not station_name:
        station_name = get_hostname()
    store = new_store()
    if branch_name:
        branch = store.find(
            Person,
            And(Person.name == branch_name,
                Branch.person_id == Person.id)).one()
    else:
        branches = store.find(Branch)
        if branches.count() == 0:
            person = Person(name=u"test", store=store)
            branch = Branch(person=person, store=store)
        else:
            branch = branches[0]

    provide_utility(ICurrentBranch, branch)

    station = BranchStation.get_station(store, branch, station_name)
    if not station:
        station = BranchStation.create(store, branch, station_name)

    assert station
    assert station.is_active

    provide_utility(ICurrentBranchStation, station)
    store.commit(close=True)
示例#14
0
 def create_employee(self, name=u"SalesPerson"):
     from stoqlib.domain.person import Employee, Individual, Person
     person = Person(name=name, store=self.store)
     Individual(person=person, store=self.store)
     return Employee(person=person,
                     role=self.create_employee_role(),
                     store=self.store)
示例#15
0
    def process_one(self, data, fields, store):
        person = Person(store=store,
                        name=data.name,
                        phone_number=data.phone_number,
                        mobile_number=data.mobile_number)

        Company(person=person,
                store=store,
                cnpj=data.cnpj,
                fancy_name=data.name,
                state_registry=data.state_registry)

        ctloc = CityLocation.get_or_create(store=store,
                                           city=data.city,
                                           state=data.state,
                                           country=data.country)
        streetnumber = data.streetnumber and int(data.streetnumber) or None
        Address(is_main_address=True,
                person=person,
                city_location=ctloc,
                store=store,
                street=data.street,
                streetnumber=streetnumber,
                district=data.district)

        Supplier(person=person, store=store)
示例#16
0
def test_get_or_create_by_document_with_cpf(store):
    assert store.find(Individual, cpf='123.456.789-10').count() == 0

    person = Person.get_or_create_by_document(store, '123.456.789-10')

    individual = store.find(Individual, cpf='123.456.789-10').one()
    assert individual is not None
    assert person is not None
示例#17
0
def test_get_or_create_by_document_with_cnpj(store):
    assert store.find(Company, cnpj='71.255.183/0001-34').count() == 0

    person = Person.get_or_create_by_document(store, '71.255.183/0001-34')

    company = store.find(Company, cnpj='71.255.183/0001-34').one()
    assert company is not None
    assert person is not None
示例#18
0
    def _get_by_doc(self, store, data, doc):
        # Extra precaution in case we ever send the cpf already formatted
        document = format_cpf(raw_document(doc))

        person = Person.get_by_document(store, document)
        if not person or not person.client:
            return data

        return self._dump_client(person.client)
示例#19
0
    def create_client(cls, store, name, cpf, address=None):
        # TODO: Add phone number
        person = Person(name=name, store=store)
        Individual(cpf=cpf, person=person, store=store)
        if address:
            cls.create_address(person, address)

        client = Client(person=person, store=store)
        return client
示例#20
0
 def create_branch(self, name=u'Dummy', phone_number=u'12345678',
                   fax_number=u'87564321'):
     from stoqlib.domain.person import Branch, Company, Person
     person = Person(name=name, phone_number=phone_number,
                     fax_number=fax_number, store=self.store)
     self.create_address(person=person)
     fancy_name = name + u' shop'
     Company(person=person, fancy_name=fancy_name,
             store=self.store)
     return Branch(person=person, store=self.store)
示例#21
0
 def next_step(self):
     if self.individual_check.get_active():
         role_type = Person.ROLE_INDIVIDUAL
     else:
         role_type = Person.ROLE_COMPANY
     phone_number = self.model.phone_number
     persons = Person.get_by_phone_number(self.store, phone_number)
     if persons.is_empty():
         return RoleEditorStep(self.wizard, self.store, self, role_type, phone_number=phone_number)
     else:
         return ExistingPersonStep(self.wizard, self.store, self, role_type, persons, phone_number=phone_number)
示例#22
0
    def next_step(self):
        if self.individual_check.get_active():
            role_type = Person.ROLE_INDIVIDUAL
        else:
            role_type = Person.ROLE_COMPANY

        # If someone wants to register with an empty document
        if self.person_document.is_empty():
            return RoleEditorStep(self.wizard, self.store, self, role_type)

        person = Person.get_by_document(self.store, self.model.person_document)
        return RoleEditorStep(self.wizard, self.store, self, role_type, person,
                              document=self.model.person_document)
示例#23
0
    def next_step(self):
        if self.individual_check.get_active():
            role_type = Person.ROLE_INDIVIDUAL
        else:
            role_type = Person.ROLE_COMPANY

        # If someone wants to register with an empty document
        if self.person_document.is_empty():
            return RoleEditorStep(self.wizard, self.store, self, role_type,
                                  description=self._description)

        person = Person.get_by_document(self.store, self.model.person_document)
        return RoleEditorStep(self.wizard, self.store, self, role_type, person,
                              document=self.model.person_document)
示例#24
0
文件: admin.py 项目: 5l1v3r1/stoq-1
def ensure_admin_user(administrator_password):
    log.info("Creating administrator user")

    default_store = get_default_store()
    user = get_admin_user(default_store)

    if user is None:
        store = new_store()
        person = Person(name=_(u'Administrator'), store=store)

        # Dependencies to create an user.
        role = EmployeeRole(name=_(u'System Administrator'), store=store)
        Individual(person=person, store=store)
        employee = Employee(person=person, role=role, store=store)
        EmployeeRoleHistory(store=store,
                            role=role,
                            employee=employee,
                            is_active=True,
                            salary=currency(800))

        # This is usefull when testing a initial database. Admin user actually
        # must have all the facets.
        SalesPerson(person=person, store=store)

        profile = store.find(UserProfile, name=_(u'Administrator')).one()
        # Backwards compatibility. this profile used to be in english
        # FIXME: Maybe its safe to assume the first profile in the table is
        # the admin.
        if not profile:
            profile = store.find(UserProfile, name=u'Administrator').one()

        log.info("Attaching a LoginUser (%s)" % (USER_ADMIN_DEFAULT_NAME, ))
        LoginUser(person=person,
                  username=USER_ADMIN_DEFAULT_NAME,
                  password=administrator_password,
                  profile=profile,
                  store=store)

        store.commit(close=True)

    # Fetch the user again, this time from the right connection
    user = get_admin_user(default_store)
    assert user

    user.set_password(administrator_password)

    # We can't provide the utility until it's actually in the database
    log.info('providing utility ICurrentUser')
    provide_utility(ICurrentUser, user)
示例#25
0
    def _get_by_doc(self, store, data, doc):
        # Extra precaution in case we ever send the cpf already formatted
        document = format_cpf(raw_document(doc))

        person = Person.get_by_document(store, document)
        if person and person.client:
            data = self._dump_client(person.client)

        # Plugins that listen to this signal will return extra fields
        # to be added to the response
        responses = signal('CheckRewardsPermissionsEvent').send(doc)
        for response in responses:
            data.update(response[1])

        return data
示例#26
0
    def process_one(self, data, fields, store):
        person = Person(
            store=store,
            name=data.name,
            phone_number=data.phone_number,
            mobile_number=data.mobile_number)

        Individual(person=person,
                   store=store,
                   cpf=data.cpf,
                   rg_number=data.rg)

        role = EmployeeRole(store=store, name=data.role)

        employee = Employee(person=person,
                            store=store,
                            role=role,
                            salary=int(data.salary),
                            registry_number=data.employee_number)

        start = self.parse_date(data.start)
        EmployeeRoleHistory(
            store=store, role=role,
            employee=employee,
            is_active=True,
            began=start,
            salary=int(data.salary))

        ctloc = CityLocation.get_or_create(store=store,
                                           city=data.city,
                                           state=data.state,
                                           country=data.country)
        streetnumber = data.streetnumber and int(data.streetnumber) or None
        Address(is_main_address=True,
                person=person,
                city_location=ctloc,
                store=store,
                street=data.street,
                streetnumber=streetnumber,
                district=data.district)

        if self.create_users:
            profile = store.find(UserProfile, name=data.profile).one()
            LoginUser(person=person, store=store, profile=profile,
                      username=data.username,
                      password=data.password)

        SalesPerson(person=person, store=store)
示例#27
0
def create_main_branch(store, name):
    """Creates a new branch and sets it as the main branch for the system
    :param store: a store
    :param name: name of the new branch
    """
    person = Person(name=name, store=store)
    Company(person=person, store=store)
    branch = Branch(person=person, store=store)

    sysparam.set_object(store, 'MAIN_COMPANY', branch)

    provide_utility(ICurrentBranch, branch)
    admin = get_admin_user(store)
    admin.add_access_to(branch)

    return branch
示例#28
0
    def _create_client(self, store):
        from stoqlib.domain.address import Address, CityLocation
        from stoqlib.domain.person import Client, Person

        person = Person(name=u'Person', store=store)
        city = CityLocation.get_default(store)
        Address(store=store,
                street=u'Rua Principal',
                streetnumber=123,
                postal_code=u'12345-678',
                is_main_address=True,
                person=person,
                city_location=city)
        client = Client(person=person, store=store)
        client.credit_limit = currency("1000")
        return client
示例#29
0
 def create_model(self, store):
     # XXX: Waiting fix for bug 2163. We should not need anymore to
     # provide empty values for mandatory attributes
     if not self.person:
         self.person = Person(name=u"", store=store)
     if not self.role_type in [Person.ROLE_INDIVIDUAL, Person.ROLE_COMPANY]:
         raise ValueError("Invalid value for role_type attribute, %r" %
                          (self.role_type, ))
     if (self.role_type == Person.ROLE_INDIVIDUAL
             and not self.person.individual):
         Individual(person=self.person, store=store, cpf=self.document)
     elif (self.role_type == Person.ROLE_COMPANY
           and not self.person.company):
         Company(person=self.person, store=store, cnpj=self.document)
     else:
         pass
     return self.person
示例#30
0
    def find_or_create_supplier(self, nfe_supplier):
        # FIXME: Need to do the same thing to Individual suppliers
        person = Person.get_or_create_by_document(
            self.store,
            nfe_supplier.cnpj,
            name=nfe_supplier.name,
            phone_number=nfe_supplier.phone_number,
            notes=u"Automatically created by Stoq-Link")

        person.company.state_registry = nfe_supplier.state_registry
        person.company.fancy_name = nfe_supplier.fancy_name or nfe_supplier.name

        if person.supplier is None:
            supplier = Supplier(store=self.store, person=person)
            nfe_supplier.supplier = supplier

        return person.supplier
示例#31
0
 def test_default_return_sales_cfop(self):
     from stoqlib.domain.fiscal import FiscalBookEntry
     self._create_examples()
     wrong_param = self.sparam.get_object(self.store, 'DEFAULT_SALES_CFOP')
     drawee = Person(name=u'Antonione', store=self.store)
     group = self.create_payment_group()
     book_entry = FiscalBookEntry(entry_type=FiscalBookEntry.TYPE_SERVICE,
                                  invoice_number=123,
                                  cfop=wrong_param,
                                  branch=self.branch,
                                  drawee=drawee,
                                  payment_group=group,
                                  iss_value=1,
                                  icms_value=0,
                                  ipi_value=0,
                                  store=self.store)
     reversal = book_entry.reverse_entry(invoice_number=124)
     self.assertEqual(wrong_param, reversal.cfop)
示例#32
0
    def _update_sale_client(self):
        """Update the sale client based on the informed document

        If the sale does not have a client yet, and the current_document (informed by
        the ecf plugin) is set, and a person with the given document exists, that client
        will be associated with this sale.
        """
        if self.model.client or not self.wizard._current_document:
            return

        person = Person.get_by_document(self.store,
                                        str(self.wizard._current_document))
        if not person:
            return

        if person.client:
            self.model.client = person.client
        else:
            self.model.client = Client(store=self.store, person=person)
示例#33
0
    def _find_branch(self, branch_id=None):
        cnpj = self._format_cnpj(self._get_text('/infNFe/dest/CNPJ',
                                                self.root))
        if branch_id:
            branch = self.store.get(Branch, branch_id)
            if cnpj != branch.person.company.cnpj:
                raise NFeDifferentCNPJ(cnpj)
        try:
            person = Person.get_by_document(self.store, cnpj)
        except NotOneError:
            # Found multiple branchs with the same CNPJ, so we get it by id
            person = self.store.get(Branch,
                                    branch_id).person if branch_id else None

        if person is None:
            return None, cnpj

        provide_utility(ICurrentBranch, person.branch, replace=True)
        return person.branch, cnpj
示例#34
0
    def _create_examples(self):
        person = Person(name=u'Jonas', store=self.store)
        Individual(person=person, store=self.store)
        role = EmployeeRole(store=self.store, name=u'desenvolvedor')
        Employee(person=person, store=self.store,
                 role=role)
        self.salesperson = SalesPerson(person=person,
                                       store=self.store)
        Company(person=person, store=self.store)
        client = Client(person=person, store=self.store)
        self.branch = Branch(person=person, store=self.store)

        group = self.create_payment_group()
        self.sale = Sale(coupon_id=123, client=client,
                         cfop_id=self.sparam.get_object_id('DEFAULT_SALES_CFOP'),
                         group=group, branch=self.branch,
                         salesperson=self.salesperson,
                         store=self.store)

        self.storable = self.create_storable()
示例#35
0
 def _fill_person_combo(self):
     items = Person.get_items(self.store,
                              Person.branch != api.get_current_branch(self.store))
     self.person.prefill(items)
示例#36
0
def apply_patch(store):
    # Creation of new column in stock_decrease table.
    # And added new Cfop to cfop_data table.
    store.execute("""ALTER TABLE stock_decrease
                   ADD COLUMN cfop_id bigint REFERENCES cfop_data(id);""")

    # Default Cfop should be use in manual stock decrease.
    cfop_data = store.find(CfopData, code=u'5.949').one()
    if not cfop_data:
        cfop_data = CfopData(store=store,
                             code=u"5.949",
                             description=u"Outra saída de mercadoria ou "
                                         u"prestação de serviço não "
                                         u"especificado")

    # Adjusting existing manuals outputs
    for stock_decrease in store.find(StockDecrease):
        stock_decrease.cfop = cfop_data

    retentions = store.execute("""
        SELECT id, quantity, reason, retention_date, product_id, cfop_id
          FROM product_retention_history ORDER BY id;""").get_all()

    # Without retentions, there is no need to create user and employee
    # variables.
    if len(retentions):

        # Default user for migration
        user = get_admin_user(store)
        if user is None:
            users = Person.iselectBy(IUser, is_active=True,
                                     store=store).order_by(Person.id)
            user = users[0]

        # Default employee for migration
        employee = IEmployee(user.person, None)
        if employee is None:
            employees = Person.iselectBy(IEmployee, is_active=True,
                                         store=store).order_by(Person.id)
            employee = employees[0]

        default_branch = sysparam(store).MAIN_COMPANY
        notes = _(u"Stock decrease imported from old retention.")

    history = store.execute("""
        SELECT id, quantity_retained, sellable_id, branch_id
          FROM product_history
         WHERE quantity_retained is not null
          ORDER BY id;""").get_all()

    for i in range(len(retentions)):
        ret = retentions[i]
        hist = history[i]

        product = Product.get(ret[4], store=store)

        branch_id = hist[3]
        if ret[1] != hist[1] or product.sellable.id != hist[2]:
            branch_id = default_branch.id

        decrease = StockDecrease(store=store,
                                 confirm_date=ret[3],
                                 status=StockDecrease.STATUS_CONFIRMED,
                                 reason=ret[2],
                                 notes=notes,
                                 responsible=user,
                                 removed_by=employee,
                                 branch_id=branch_id,
                                 cfop_id=ret[5])

        decrease_item = StockDecreaseItem(store=store,
                                          quantity=ret[1],
                                          sellable=product.sellable)
        decrease.add_item(decrease_item)

        ProductHistory.delete(hist[0], store)
        ProductHistory(branch_id=branch_id, sellable=product.sellable,
                       quantity_decreased=decrease_item.quantity,
                       decreased_date=decrease.confirm_date,
                       store=store)

    store.execute("""ALTER TABLE product_history
                   DROP COLUMN quantity_retained;""")
    store.execute("DROP TABLE product_retention_history;")