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())
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)
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())
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()
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
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)
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())
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()
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)
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)
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)
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)
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)
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
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)
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
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)
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