Example #1
0
    def pay(self, paid_date=None, paid_value=None, account=None):
        """Pay the current payment set its status as :obj:`.STATUS_PAID`"""
        if self.status != Payment.STATUS_PENDING:
            raise ValueError(_(u"This payment is already paid."))
        self._check_status(self.STATUS_PENDING, u'pay')

        paid_value = paid_value or (self.value - self.discount +
                                    self.interest)
        self.paid_value = paid_value
        self.paid_date = paid_date or TransactionTimestamp()
        self.status = self.STATUS_PAID

        if (self.is_separate_payment() or
            self.method.operation.create_transaction()):
            AccountTransaction.create_from_payment(self, account)

        sale = self.group and self.group.sale
        if sale:
            transaction = IPaymentTransaction(sale)
            transaction.create_commission(self)

        if self.value == self.paid_value:
            msg = _(u"{method} payment with value {value:.2f} was paid").format(
                    method=self.method.method_name,
                    value=self.value)
        else:
            msg = _(u"{method} payment with value original value "
                    u"{original_value:.2f} was paid with value "
                    u"{value:.2f}").format(
                    method=self.method.method_name,
                    original_value=self.value,
                    value=self.paid_value)
        Event.log(Event.TYPE_PAYMENT, msg.capitalize())
Example #2
0
 def test_get_inverted_operation(self):
     # IN -> OUT
     operation_type = AccountTransaction.TYPE_IN
     inverted_type = AccountTransaction.get_inverted_operation_type(operation_type)
     self.assertEqual(inverted_type, AccountTransaction.TYPE_OUT)
     # OUT -> IN
     operation_type = AccountTransaction.TYPE_OUT
     inverted_type = AccountTransaction.get_inverted_operation_type(operation_type)
     self.assertEqual(inverted_type, AccountTransaction.TYPE_IN)
Example #3
0
 def test_get_inverted_operation(self):
     # IN -> OUT
     operation_type = AccountTransaction.TYPE_IN
     inverted_type = AccountTransaction.get_inverted_operation_type(operation_type)
     self.assertEqual(inverted_type, AccountTransaction.TYPE_OUT)
     # OUT -> IN
     operation_type = AccountTransaction.TYPE_OUT
     inverted_type = AccountTransaction.get_inverted_operation_type(operation_type)
     self.assertEqual(inverted_type, AccountTransaction.TYPE_IN)
Example #4
0
    def pay(self,
            paid_date=None,
            paid_value=None,
            source_account=None,
            destination_account=None,
            account_transaction_number=None):
        """Pay the current payment set its status as :obj:`.STATUS_PAID`

        If this payment belongs to a sale, and all other payments from the sale
        are paid then the sale will be set as paid.
        """
        if self.status != Payment.STATUS_PENDING:
            raise ValueError(_(u"This payment is already paid."))
        self._check_status(self.STATUS_PENDING, u'pay')

        paid_value = paid_value or (self.value - self.discount + self.interest)
        self.paid_value = paid_value
        self.paid_date = paid_date or TransactionTimestamp()
        self.status = self.STATUS_PAID

        if (self.is_separate_payment()
                or self.method.operation.create_transaction()):
            AccountTransaction.create_from_payment(
                self,
                code=account_transaction_number,
                source_account=source_account,
                destination_account=destination_account)

        sale = self.group and self.group.sale
        if sale:
            sale.create_commission(self)

            # When paying payments of a sale, check if the other payments are
            # paid. If they are, this means you can change the sale status to
            # paid as well.
            if sale.can_set_paid():
                sale.set_paid()

        if self.value == self.paid_value:
            msg = _(
                u"{method} payment with value {value:.2f} was paid").format(
                    method=self.method.method_name, value=self.value)
        else:
            msg = _(u"{method} payment with value original value "
                    u"{original_value:.2f} was paid with value "
                    u"{value:.2f}").format(method=self.method.method_name,
                                           original_value=self.value,
                                           value=self.paid_value)
        Event.log(self.store, Event.TYPE_PAYMENT, msg.capitalize())
Example #5
0
    def _import_transaction(self, store, node):
        date_text = self._get_text(node, '%s/%s' % (_trnns('date-posted'),
                                                    _tsns('date')))
        date = self._parse_date(date_text)

        splits = node.findall('%s/%s' % (_trnns('splits'),
                                         _trnns('split')))
        dest_node = splits[0]
        source_node = splits[1]

        source = self._get_text(source_node, _splitns('account'))
        source_account = self._accounts[source]
        assert source_account, ElementTree.tostring(source_node)

        dest = self._get_text(dest_node, _splitns('account'))
        dest_account = self._accounts[dest]
        assert dest_account, ElementTree.tostring(dest_node)

        text_value = self._get_text(dest_node, _splitns('value'))
        values = text_value.split('/', 2)
        value = decimal.Decimal(values[0]) / decimal.Decimal(values[1])

        if len(splits) != 2:
            # If we have a split to the same account, just merge them until
            # we support split transactions
            accounts = []
            diff = False
            for split_node in splits[2:]:
                split = self._get_text(split_node, _splitns('account'))
                if split != source:
                    diff = True
                accounts.append(self._accounts[split])

            if diff:
                log.info("Can't do splits to different accounts: %s->%s" % (
                    dest_account.description, ', '.join(repr(a.description)
                                                        for a in accounts)))
                return

        at = AccountTransaction(
            account=dest_account,
            source_account=source_account,
            description=self._get_text(node, _trnns('description')),
            code=self._get_text(node, _trnns('num')),
            date=date,
            value=value,
            store=store)
        at.sync()
Example #6
0
    def process_item(self, store, i):
        t = self.tp.transactions[i]
        date = self._parse_date(t['dtposted'])
        # Do not import transactions with broken dates
        if date is None:
            self.skipped += 1
            return False

        value = self._parse_number(t['trnamt'])
        if value == 0:
            self.skipped += 1
            # We can't import transactions with a value = 0, skip it.
            return False
        source_account = store.get(Account, self.source_account_id)
        account = store.get(Account, self.account_id)

        code = self._parse_string(t['checknum'])
        if not store.find(
                AccountTransaction, date=date, code=code,
                value=value).is_empty():
            # Skip already present transactions
            self.skipped += 1
            return False
        t = AccountTransaction(source_account=source_account,
                               account=account,
                               description=self._parse_string(t['memo']),
                               code=code,
                               value=value,
                               date=date,
                               store=store)
        store.flush()
        return True
Example #7
0
def _create_transaction(store, till_entry):
    # Dont create till entries for sangrias/suprimentos as those are really tied to the
    # old ECF behaivour (where *all* the sales values are added to the till). If we
    # create transactions for those operations, the value would be duplicated when the
    # payment is finally payed.
    if not till_entry.payment:
        return

    if till_entry.value > 0:
        operation_type = AccountTransaction.TYPE_IN
        source_account = sysparam.get_object_id('IMBALANCE_ACCOUNT')
        dest_account = sysparam.get_object_id('TILLS_ACCOUNT')
    else:
        operation_type = AccountTransaction.TYPE_OUT
        source_account = sysparam.get_object_id('TILLS_ACCOUNT')
        dest_account = sysparam.get_object_id('IMBALANCE_ACCOUNT')

    AccountTransaction(description=till_entry.description,
                       source_account_id=source_account,
                       account_id=dest_account,
                       value=abs(till_entry.value),
                       code=str(till_entry.identifier),
                       date=TransactionTimestamp(),
                       store=store,
                       payment=till_entry.payment,
                       operation_type=operation_type)
Example #8
0
    def pay(self, paid_date=None, paid_value=None,
            source_account=None, destination_account=None,
            account_transaction_number=None):
        """Pay the current payment set its status as :obj:`.STATUS_PAID`

        If this payment belongs to a sale, and all other payments from the sale
        are paid then the sale will be set as paid.
        """
        if self.status != Payment.STATUS_PENDING:
            raise ValueError(_(u"This payment is already paid."))
        self._check_status(self.STATUS_PENDING, u'pay')

        paid_value = paid_value or (self.value - self.discount +
                                    self.interest)
        self.paid_value = paid_value
        self.paid_date = paid_date or TransactionTimestamp()
        self.status = self.STATUS_PAID

        if (self.is_separate_payment() or
                self.method.operation.create_transaction()):
            AccountTransaction.create_from_payment(
                self,
                code=account_transaction_number,
                source_account=source_account,
                destination_account=destination_account)

        sale = self.group and self.group.sale
        if sale:
            sale.create_commission(self)

            # When paying payments of a sale, check if the other payments are
            # paid. If they are, this means you can change the sale status to
            # paid as well.
            if sale.can_set_paid():
                sale.set_paid()

        if self.value == self.paid_value:
            msg = _(u"{method} payment with value {value:.2f} was paid").format(
                method=self.method.method_name,
                value=self.value)
        else:
            msg = _(u"{method} payment with value original value "
                    u"{original_value:.2f} was paid with value "
                    u"{value:.2f}").format(method=self.method.method_name,
                                           original_value=self.value,
                                           value=self.paid_value)
        Event.log(self.store, Event.TYPE_PAYMENT, msg.capitalize())
Example #9
0
    def _import_transaction(self, store, node):
        date_text = self._get_text(
            node, '%s/%s' % (_trnns('date-posted'), _tsns('date')))
        date = self._parse_date(date_text)

        splits = node.findall('%s/%s' % (_trnns('splits'), _trnns('split')))
        dest_node = splits[0]
        source_node = splits[1]

        source = self._get_text(source_node, _splitns('account'))
        source_account = self._accounts[source]
        assert source_account, ElementTree.tostring(source_node)

        dest = self._get_text(dest_node, _splitns('account'))
        dest_account = self._accounts[dest]
        assert dest_account, ElementTree.tostring(dest_node)

        text_value = self._get_text(dest_node, _splitns('value'))
        values = text_value.split('/', 2)
        value = decimal.Decimal(values[0]) / decimal.Decimal(values[1])

        if len(splits) != 2:
            # If we have a split to the same account, just merge them until
            # we support split transactions
            accounts = []
            diff = False
            for split_node in splits[2:]:
                split = self._get_text(split_node, _splitns('account'))
                if split != source:
                    diff = True
                accounts.append(self._accounts[split])

            if diff:
                log.info("Can't do splits to different accounts: %s->%s" %
                         (dest_account.description, ', '.join(
                             repr(a.description) for a in accounts)))
                return

        at = AccountTransaction(account=dest_account,
                                source_account=source_account,
                                description=self._get_text(
                                    node, _trnns('description')),
                                code=self._get_text(node, _trnns('num')),
                                date=date,
                                value=value,
                                store=store)
        at.sync()
Example #10
0
def _create_transaction(store, till_entry):
    AccountTransaction(description=till_entry.description,
                       source_account=sysparam(store).IMBALANCE_ACCOUNT,
                       account=sysparam(store).TILLS_ACCOUNT,
                       value=till_entry.value,
                       code=unicode(till_entry.id),
                       date=TransactionTimestamp(),
                       store=store,
                       payment=till_entry.payment)
Example #11
0
 def create_model(self, store):
     return AccountTransaction(code=u"",
                               description=u"",
                               value=currency(0),
                               payment=None,
                               date=datetime.datetime.today(),
                               account=sysparam.get_object(store, 'IMBALANCE_ACCOUNT'),
                               source_account=self.parent_account,
                               operation_type=AccountTransaction.TYPE_OUT,
                               store=store)
    def process_one(self, data, fields, store):
        source = self._get_account(store, data.parent_source, data.source)
        dest = self._get_account(store, data.parent_dest, data.dest)

        AccountTransaction(account=dest,
                           source_account=source,
                           description=data.description,
                           value=decimal.Decimal(data.value),
                           date=self.parse_date(data.date),
                           code=data.code,
                           store=store)
Example #13
0
 def create_account_transaction(self, account=None, value=1):
     from stoqlib.domain.account import AccountTransaction
     if account is None:
         account = self.create_account()
     return AccountTransaction(description=u"Test Account Transaction",
                               code=u"Code",
                               date=localnow(),
                               value=value,
                               account=account,
                               source_account=sysparam(
                                   self.store).IMBALANCE_ACCOUNT,
                               store=self.store)
Example #14
0
    def test_create_from_payment(self):
        sale = self.create_sale()
        self.add_product(sale)
        payment = self.add_payments(sale, method_type=u'check')[0]
        sale.order()
        sale.confirm()
        account = self.create_account()
        payment.method.destination_account = account
        self.assertRaises(PaymentError, AccountTransaction.create_from_payment,
                          payment)
        payment.pay()
        transaction = AccountTransaction.create_from_payment(payment)

        imbalance_account = sysparam(self.store).IMBALANCE_ACCOUNT
        self.assertEquals(transaction.source_account, imbalance_account)
        self.assertEquals(transaction.account, account)
        self.assertEquals(transaction.payment, payment)
Example #15
0
    def test_create_from_payment(self):
        sale = self.create_sale()
        self.add_product(sale)
        payment = self.add_payments(sale, method_type=u'check')[0]
        sale.order()
        sale.confirm()
        account = self.create_account()
        payment.method.destination_account = account
        self.assertRaises(PaymentError,
                          AccountTransaction.create_from_payment, payment)
        payment.pay()
        transaction = AccountTransaction.create_from_payment(payment)

        imbalance_account = sysparam.get_object(self.store, 'IMBALANCE_ACCOUNT')
        self.assertEquals(transaction.source_account, imbalance_account)
        self.assertEquals(transaction.account, account)
        self.assertEquals(transaction.payment, payment)
Example #16
0
    def to_domain(self):
        if not self.is_incoming:
            self.value *= currency(-1)

        fields = dict(code=self.code,
                      description=self.description,
                      date=self.date,
                      value=self.value,
                      account=self.account,
                      payment=self.payment,
                      source_account=self.source_account)
        if self.transaction:
            t = self.transaction
            for k, v in fields.items():
                setattr(t, k, v)
        else:
            t = AccountTransaction(store=self.store, **fields)

        return t
Example #17
0
def _create_transaction(store, till_entry):
    if till_entry.value > 0:
        operation_type = AccountTransaction.TYPE_IN
        source_account = sysparam.get_object_id('IMBALANCE_ACCOUNT')
        dest_account = sysparam.get_object_id('TILLS_ACCOUNT')
    else:
        operation_type = AccountTransaction.TYPE_OUT
        source_account = sysparam.get_object_id('TILLS_ACCOUNT')
        dest_account = sysparam.get_object_id('IMBALANCE_ACCOUNT')

    AccountTransaction(description=till_entry.description,
                       source_account_id=source_account,
                       account_id=dest_account,
                       value=abs(till_entry.value),
                       code=str(till_entry.identifier),
                       date=TransactionTimestamp(),
                       store=store,
                       payment=till_entry.payment,
                       operation_type=operation_type)
Example #18
0
    def process_item(self, store, i):
        t = self.tp.transactions[i]
        date = self._parse_date(t['dtposted'])
        # Do not import transactions with broken dates
        if date is None:
            self.skipped += 1
            return False

        value = self._parse_number(t['trnamt'])

        if value == 0:
            self.skipped += 1
            # We can't import transactions without a value = 0, skip it.
            return False
        elif value > 0:
            operation_type = AccountTransaction.TYPE_IN
            source_account = store.get(Account, self.source_account_id)
            account = store.get(Account, self.account_id)
        elif value < 0:
            # Only register absolute values - Indicating positive/negative values,
            # using the operation type.
            value = abs(value)
            operation_type = AccountTransaction.TYPE_OUT
            source_account = store.get(Account, self.account_id)
            account = store.get(Account, self.source_account_id)

        code = self._parse_string(t['checknum'])
        if not store.find(
                AccountTransaction, date=date, code=code,
                value=value).is_empty():
            # Skip already present transactions
            self.skipped += 1
            return False
        t = AccountTransaction(source_account=source_account,
                               account=account,
                               description=self._parse_string(t['memo']),
                               code=code,
                               value=value,
                               date=date,
                               operation_type=operation_type,
                               store=store)
        store.flush()
        return True
Example #19
0
    def test_create_from_payment(self):
        sale = self.create_sale()
        self.add_product(sale)
        payment = self.add_payments(sale, method_type=u'check')[0]
        sale.order()
        sale.confirm()
        account = self.create_account()
        payment.method.destination_account = account
        with self.assertRaisesRegex(PaymentError, "Payment needs to be paid"):
            AccountTransaction.create_from_payment(payment)
        payment.pay()
        transaction = AccountTransaction.create_from_payment(payment)

        imbalance_account = sysparam.get_object(self.store,
                                                'IMBALANCE_ACCOUNT')
        self.assertEqual(transaction.source_account, imbalance_account)
        self.assertEqual(transaction.account, account)
        self.assertEqual(transaction.payment, payment)
        self.assertEqual(transaction.operation_type,
                         AccountTransaction.TYPE_IN)

        # Payment from purchase.
        purchase = self.create_purchase_order()
        purchase.status = PurchaseOrder.ORDER_PENDING
        purchase.add_item(self.create_sellable(), 1)
        payment = self.add_payments(purchase, method_type=u'money')[0]
        purchase.confirm()
        account = self.create_account()
        payment.method.destination_account = account
        with self.assertRaisesRegex(PaymentError, "Payment needs to be paid"):
            AccountTransaction.create_from_payment(payment)

        payment.pay()
        transaction = AccountTransaction.create_from_payment(payment)
        imbalance_account = sysparam.get_object(self.store,
                                                'IMBALANCE_ACCOUNT')
        self.assertEqual(transaction.source_account, account)
        self.assertEqual(transaction.account, imbalance_account)
        self.assertEqual(transaction.payment, payment)
        self.assertEqual(transaction.operation_type,
                         AccountTransaction.TYPE_OUT)
Example #20
0
    def test_create_from_payment(self):
        sale = self.create_sale()
        self.add_product(sale)
        payment = self.add_payments(sale, method_type=u'check')[0]
        sale.order()
        sale.confirm()
        account = self.create_account()
        payment.method.destination_account = account
        with self.assertRaisesRegex(PaymentError, "Payment needs to be paid"):
            AccountTransaction.create_from_payment(payment)
        payment.pay()
        transaction = AccountTransaction.create_from_payment(payment)

        imbalance_account = sysparam.get_object(self.store, 'IMBALANCE_ACCOUNT')
        self.assertEqual(transaction.source_account, imbalance_account)
        self.assertEqual(transaction.account, account)
        self.assertEqual(transaction.payment, payment)
        self.assertEqual(transaction.operation_type, AccountTransaction.TYPE_IN)

        # Payment from purchase.
        purchase = self.create_purchase_order()
        purchase.status = PurchaseOrder.ORDER_PENDING
        purchase.add_item(self.create_sellable(), 1)
        payment = self.add_payments(purchase, method_type=u'money')[0]
        purchase.confirm()
        account = self.create_account()
        payment.method.destination_account = account
        with self.assertRaisesRegex(PaymentError, "Payment needs to be paid"):
            AccountTransaction.create_from_payment(payment)

        payment.pay()
        transaction = AccountTransaction.create_from_payment(payment)
        imbalance_account = sysparam.get_object(self.store, 'IMBALANCE_ACCOUNT')
        self.assertEqual(transaction.source_account, account)
        self.assertEqual(transaction.account, imbalance_account)
        self.assertEqual(transaction.payment, payment)
        self.assertEqual(transaction.operation_type, AccountTransaction.TYPE_OUT)
Example #21
0
    def process_item(self, store, i):
        t = self.tp.transactions[i]
        date = self._parse_date(t['dtposted'])
        # Do not import transactions with broken dates
        if date is None:
            self.skipped += 1
            return False

        value = self._parse_number(t['trnamt'])
        description = self._parse_string(t['memo'])

        if value == 0:
            self.skipped += 1
            # We can't import transactions without a value = 0, skip it.
            return False
        elif value > 0:
            operation_type = AccountTransaction.TYPE_IN
            source_account = store.get(Account, self.source_account_id)
            account = store.get(Account, self.account_id)
        elif value < 0:
            # Only register absolute values - Indicating positive/negative values,
            # using the operation type.
            value = abs(value)
            operation_type = AccountTransaction.TYPE_OUT
            source_account = store.get(Account, self.account_id)
            account = store.get(Account, self.source_account_id)

        code = self._parse_string(t['checknum'])
        if not store.find(
                AccountTransaction, date=date, code=code,
                value=value).is_empty():
            # Skip already present transactions
            self.skipped += 1
            return False

        # TODO: Check if value and code are enough to consider a match.
        existing = list(
            store.find(
                AccountTransaction,
                And(
                    AccountTransaction.value == value,
                    Trim(u'LEADING', u'0',
                         AccountTransaction.code) == code.lstrip('0'))))
        if len(existing) == 1:
            t = existing[0]
            t.description = description
            t.date = date

            # Categorize the transaction if it was still on imbalance
            if sysparam.compare_object('IMBALANCE_ACCOUNT', t.source_account):
                t.source_account = source_account
            if sysparam.compare_object('IMBALANCE_ACCOUNT', t.account):
                t.account = account
        else:
            t = AccountTransaction(store=store,
                                   source_account=source_account,
                                   account=account,
                                   description=description,
                                   code=code,
                                   value=value,
                                   date=date,
                                   operation_type=operation_type)

        store.flush()
        return True