Module jumpscale.sals.billing.models
Expand source code
from jumpscale.core.base import Base, fields, StoredFactory
import datetime
from jumpscale.loader import j
from jumpscale.clients.stellar import TRANSACTION_FEES
from decimal import Decimal
import datetime
class PaymentTransactionRefund(Base):
    refund_transaction_hash = fields.String()
    success = fields.Boolean(default=False)
class PaymentTransaction(Base):
    transaction_hash = fields.String(required=True)
    transaction_refund = fields.Object(PaymentTransactionRefund)
    success = fields.Boolean(default=False)
    def refund(self, wallet):
        if self.transaction_refund.success:
            return True
        try:
            amount = round(self.get_amount(wallet) - Decimal(TRANSACTION_FEES), 6)
            if amount < 0:
                self.transaction_refund.success = True
            else:
                a = wallet._get_asset()
                sender_address = wallet.get_sender_wallet_address(self.transaction_hash)
                j.logger.info(
                    f"refunding transaction: {self.transaction_hash} with amount: {amount} to address: {sender_address}"
                )
                self.transaction_refund.transaction_hash = wallet.transfer(
                    sender_address, amount=amount, asset=f"{a.code}:{a.issuer}"
                )
                self.transaction_refund.success = True
                j.logger.info(
                    f"transaction: {self.transaction_hash} refunded successfully with amount: {amount} to address: {sender_address} in transaction: {self.transaction_refund.transaction_hash}"
                )
        except Exception as e:
            j.logger.critical(f"failed to refund transaction: {self.transaction_hash} due to error: {str(e)}")
        return self.transaction_refund.success
    def get_amount(self, wallet):
        try:
            effects = wallet.get_transaction_effects(self.transaction_hash)
        except Exception as e:
            j.logger.warning(f"failed to get transaction effects of hash {self.transaction_hash} due to error {str(e)}")
            raise e
        trans_amount = 0
        for effect in effects:
            if effect.asset_code != "TFT":
                continue
            trans_amount += effect.amount
        return trans_amount
class PaymentResult(Base):
    success = fields.Boolean(default=False)
    extra_paid = fields.Boolean(default=False)
    transactions = fields.List(fields.Object(PaymentTransaction))
    def refund_extra(self):
        if self.extra_paid and self.parent.refund_extra:
            for transaction in self.transactions:
                if transaction.success:
                    trans_amount = transaction.get_amount(self.parent.wallet)
                    diff = float(trans_amount) - self.parent.amount
                    if diff <= TRANSACTION_FEES:
                        self.extra_paid = False
                        break
                    sender_address = self.parent.wallet.get_sender_wallet_address(transaction.transaction_hash)
                    amount = round(diff - TRANSACTION_FEES, 6)
                    try:
                        j.logger.info(
                            f"refunding extra amount: {amount} of transaction {transaction.transaction_hash} to address: {sender_address}"
                        )
                        a = self.parent.wallet._get_asset()
                        refund_hash = self.parent.wallet.transfer(
                            sender_address, amount=amount, asset=f"{a.code}:{a.issuer}"
                        )
                        self.extra_paid = False
                        j.logger.info(
                            f"extra amount: {amount} of transaction {transaction.transaction_hash} refunded successfully in transaction: {refund_hash} to address: {sender_address}"
                        )
                    except Exception as e:
                        j.logger.critical(
                            f"failed to refund extra amount {amount} for payment: {self.parent.payment_id} due to error: {str(e)}"
                        )
            self.parent.save()
        return self.extra_paid
class Payment(Base):
    payment_id = fields.String()
    wallet_name = fields.String(required=True)
    amount = fields.Float(required=True)
    memo_text = fields.String(default=lambda: j.data.idgenerator.chars(28))
    created_at = fields.DateTime(default=datetime.datetime.utcnow)
    deadline = fields.DateTime(default=lambda: datetime.datetime.utcnow() + datetime.timedelta(minutes=5))
    result = fields.Object(PaymentResult, required=True)
    refund_extra = fields.Boolean(default=True)
    description = fields.String()
    def is_finished(self):
        if self.deadline.timestamp() < j.data.time.utcnow().timestamp or self.result.success:
            return True
        return False
    @property
    def wallet(self):
        return j.clients.stellar.get(self.wallet_name)
    def update_status(self):
        if self.is_finished():
            return
        if self.amount == 0:
            self.result.success = True
            self.save()
            return
        j.logger.info(f"updating payment: {self.payment_id} status")
        transactions = self.wallet.list_transactions()
        current_transactions = {t.transaction_hash: t for t in self.result.transactions}
        for transaction in transactions:
            transaction_hash = transaction.hash
            if transaction_hash in current_transactions:
                continue
            trans_memo_text = transaction.memo_text
            if not trans_memo_text:
                continue
            if trans_memo_text != self.memo_text:
                continue
            j.logger.info(f"adding transaction {transaction_hash} to payment: {self.payment_id}")
            trans_obj = PaymentTransaction()
            trans_obj.transaction_hash = transaction_hash
            self.result.transactions.append(trans_obj)
            if not self.result.success:
                try:
                    trans_amount = trans_obj.get_amount(self.wallet)
                    j.logger.info(
                        f"adding transaction {transaction_hash} to payment: {self.payment_id} with amount: {trans_amount}"
                    )
                except Exception as e:
                    j.logger.error(
                        f"failed to update payment {self.instance_name} with transaction {transaction_hash} due to error {str(e)}"
                    )
                    continue
                if trans_amount >= Decimal(self.amount) or abs(trans_amount - Decimal(self.amount)) <= 0.000001:
                    j.logger.info(
                        f"payment: {self.payment_id} fulfilled by transaction: {transaction_hash} with amount: {trans_amount}"
                    )
                    trans_obj.success = True
                    self.result.success = True
                    if trans_amount > Decimal(self.amount):
                        j.logger.info(f"payment: {self.payment_id} is marked as extra paid")
                        self.result.extra_paid = True
            self.save()
class PaymentFactory(StoredFactory):
    def find_by_id(self, payment_id):
        instance_name = f"payment_{payment_id}"
        return self.find(instance_name)
    def list_failed_payments(self):
        for name in self.list_all():
            payment = self.find(name)
            payment.update_status()
            if payment.is_finished():
                if not payment.result.success:
                    yield payment
                else:
                    for transaction in payment.result.transactions:
                        if not transaction.success and not transaction.transaction_refund.success:
                            yield payment
                            break
    def list_active_payments(self):
        for name in self.list_all():
            payment = self.find(name)
            if not payment.is_finished():
                yield payment
    def list_extra_paid_payments(self):
        _, _, payments = self.find_many(refund_extra=True)
        for payment in payments:
            if payment.result.extra_paid and payment.is_finished():
                yield payment
PAYMENT_FACTORY = PaymentFactory(Payment)
PAYMENT_FACTORY.always_reload = True
class RefundRequest(Base):
    payment_id = fields.String(required=True)
    success = fields.Boolean(default=False)
    refund_transaction_hash = fields.String()
    last_tried = fields.DateTime()
    amount = fields.Float(default=-1)
    def apply(self):
        payment = PAYMENT_FACTORY.find_by_id(self.payment_id)
        if not payment.is_finished():
            j.logger.warning(f"can't refund active payment {self.payment_id}")
            return False
        self.last_tried = datetime.datetime.utcnow()
        amount = payment.amount
        # check if refund extra is False. then amount should be same as successful transaction in case of extra was paid but not refunded automatically
        sender_address = None
        for transaction in payment.result.transactions:
            if transaction.success:
                sender_address = payment.wallet.get_sender_wallet_address(transaction.transaction_hash)
                if not payment.refund_extra:
                    amount = float(transaction.get_amount(payment.wallet))
        # if a specific amount was specified by the refund request
        if self.amount > 0:
            amount = self.amount
        if amount <= TRANSACTION_FEES or not sender_address:
            self.success = True
        else:
            try:
                a = payment.wallet._get_asset()
                self.refund_transaction_hash = payment.wallet.transfer(
                    sender_address, amount=round(amount - TRANSACTION_FEES, 6), asset=f"{a.code}:{a.issuer}"
                )
                self.success = True
                j.logger.info(
                    f"refund request successful for payment: {self.payment_id} amount: {amount} to address: {sender_address} in transaction: {self.refund_transaction_hash}"
                )
            except Exception as e:
                j.logger.critical(f"failed to apply refund request for payment {self.payment_id} due to error {str(e)}")
        self.save()
        return self.success
class RefundFactory(StoredFactory):
    def list_active_requests(self):
        _, _, refunds = self.find_many(success=False)
        return refunds
REFUND_FACTORY = RefundFactory(RefundRequest)
REFUND_FACTORY.always_reload = True
Classes
class Payment (parent_=None, instance_name_=None, **values)- 
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)Args
parent_:Base, optional- parent instance. Defaults to None.
 instance_name_:str, optional- instance name. Defaults to None.
 **values- any given field values to initiate the instance with
 
Expand source code
class Payment(Base): payment_id = fields.String() wallet_name = fields.String(required=True) amount = fields.Float(required=True) memo_text = fields.String(default=lambda: j.data.idgenerator.chars(28)) created_at = fields.DateTime(default=datetime.datetime.utcnow) deadline = fields.DateTime(default=lambda: datetime.datetime.utcnow() + datetime.timedelta(minutes=5)) result = fields.Object(PaymentResult, required=True) refund_extra = fields.Boolean(default=True) description = fields.String() def is_finished(self): if self.deadline.timestamp() < j.data.time.utcnow().timestamp or self.result.success: return True return False @property def wallet(self): return j.clients.stellar.get(self.wallet_name) def update_status(self): if self.is_finished(): return if self.amount == 0: self.result.success = True self.save() return j.logger.info(f"updating payment: {self.payment_id} status") transactions = self.wallet.list_transactions() current_transactions = {t.transaction_hash: t for t in self.result.transactions} for transaction in transactions: transaction_hash = transaction.hash if transaction_hash in current_transactions: continue trans_memo_text = transaction.memo_text if not trans_memo_text: continue if trans_memo_text != self.memo_text: continue j.logger.info(f"adding transaction {transaction_hash} to payment: {self.payment_id}") trans_obj = PaymentTransaction() trans_obj.transaction_hash = transaction_hash self.result.transactions.append(trans_obj) if not self.result.success: try: trans_amount = trans_obj.get_amount(self.wallet) j.logger.info( f"adding transaction {transaction_hash} to payment: {self.payment_id} with amount: {trans_amount}" ) except Exception as e: j.logger.error( f"failed to update payment {self.instance_name} with transaction {transaction_hash} due to error {str(e)}" ) continue if trans_amount >= Decimal(self.amount) or abs(trans_amount - Decimal(self.amount)) <= 0.000001: j.logger.info( f"payment: {self.payment_id} fulfilled by transaction: {transaction_hash} with amount: {trans_amount}" ) trans_obj.success = True self.result.success = True if trans_amount > Decimal(self.amount): j.logger.info(f"payment: {self.payment_id} is marked as extra paid") self.result.extra_paid = True self.save()Ancestors
- Base
 - types.SimpleNamespace
 
Instance variables
var amount- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var created_at- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var deadline- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var description- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var memo_text- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var payment_id- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var refund_extra- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var result- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var wallet- 
Expand source code
@property def wallet(self): return j.clients.stellar.get(self.wallet_name) var wallet_name- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) 
Methods
def is_finished(self)- 
Expand source code
def is_finished(self): if self.deadline.timestamp() < j.data.time.utcnow().timestamp or self.result.success: return True return False def update_status(self)- 
Expand source code
def update_status(self): if self.is_finished(): return if self.amount == 0: self.result.success = True self.save() return j.logger.info(f"updating payment: {self.payment_id} status") transactions = self.wallet.list_transactions() current_transactions = {t.transaction_hash: t for t in self.result.transactions} for transaction in transactions: transaction_hash = transaction.hash if transaction_hash in current_transactions: continue trans_memo_text = transaction.memo_text if not trans_memo_text: continue if trans_memo_text != self.memo_text: continue j.logger.info(f"adding transaction {transaction_hash} to payment: {self.payment_id}") trans_obj = PaymentTransaction() trans_obj.transaction_hash = transaction_hash self.result.transactions.append(trans_obj) if not self.result.success: try: trans_amount = trans_obj.get_amount(self.wallet) j.logger.info( f"adding transaction {transaction_hash} to payment: {self.payment_id} with amount: {trans_amount}" ) except Exception as e: j.logger.error( f"failed to update payment {self.instance_name} with transaction {transaction_hash} due to error {str(e)}" ) continue if trans_amount >= Decimal(self.amount) or abs(trans_amount - Decimal(self.amount)) <= 0.000001: j.logger.info( f"payment: {self.payment_id} fulfilled by transaction: {transaction_hash} with amount: {trans_amount}" ) trans_obj.success = True self.result.success = True if trans_amount > Decimal(self.amount): j.logger.info(f"payment: {self.payment_id} is marked as extra paid") self.result.extra_paid = True self.save() 
Inherited members
 class PaymentFactory (type_, name_=None, parent_instance_=None, parent_factory_=None)- 
Stored factories are a custom type of
Factory, which uses current configured store backend to store all instance configurations.get a new stored factory given the type to create and store instances for.
Any factory can have a name, parent
Baseinstance and a parent factory.Once a stored factory is created, it tries to lazy-load all current configuration for given
type_.Args
type_:BaseBaseclass typename_:str, optional- factory name. Defaults to None.
 parent_instance_:Base, optional- a parent 
Baseinstance. Defaults to None. parent_factory_:Factory, optional- a parent 
Factory. Defaults to None. 
Expand source code
class PaymentFactory(StoredFactory): def find_by_id(self, payment_id): instance_name = f"payment_{payment_id}" return self.find(instance_name) def list_failed_payments(self): for name in self.list_all(): payment = self.find(name) payment.update_status() if payment.is_finished(): if not payment.result.success: yield payment else: for transaction in payment.result.transactions: if not transaction.success and not transaction.transaction_refund.success: yield payment break def list_active_payments(self): for name in self.list_all(): payment = self.find(name) if not payment.is_finished(): yield payment def list_extra_paid_payments(self): _, _, payments = self.find_many(refund_extra=True) for payment in payments: if payment.result.extra_paid and payment.is_finished(): yield paymentAncestors
Subclasses
- jumpscale.core.base.factory.PaymentFactory
 
Methods
def find_by_id(self, payment_id)- 
Expand source code
def find_by_id(self, payment_id): instance_name = f"payment_{payment_id}" return self.find(instance_name) def list_active_payments(self)- 
Expand source code
def list_active_payments(self): for name in self.list_all(): payment = self.find(name) if not payment.is_finished(): yield payment def list_extra_paid_payments(self)- 
Expand source code
def list_extra_paid_payments(self): _, _, payments = self.find_many(refund_extra=True) for payment in payments: if payment.result.extra_paid and payment.is_finished(): yield payment def list_failed_payments(self)- 
Expand source code
def list_failed_payments(self): for name in self.list_all(): payment = self.find(name) payment.update_status() if payment.is_finished(): if not payment.result.success: yield payment else: for transaction in payment.result.transactions: if not transaction.success and not transaction.transaction_refund.success: yield payment break 
Inherited members
 class PaymentResult (parent_=None, instance_name_=None, **values)- 
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)Args
parent_:Base, optional- parent instance. Defaults to None.
 instance_name_:str, optional- instance name. Defaults to None.
 **values- any given field values to initiate the instance with
 
Expand source code
class PaymentResult(Base): success = fields.Boolean(default=False) extra_paid = fields.Boolean(default=False) transactions = fields.List(fields.Object(PaymentTransaction)) def refund_extra(self): if self.extra_paid and self.parent.refund_extra: for transaction in self.transactions: if transaction.success: trans_amount = transaction.get_amount(self.parent.wallet) diff = float(trans_amount) - self.parent.amount if diff <= TRANSACTION_FEES: self.extra_paid = False break sender_address = self.parent.wallet.get_sender_wallet_address(transaction.transaction_hash) amount = round(diff - TRANSACTION_FEES, 6) try: j.logger.info( f"refunding extra amount: {amount} of transaction {transaction.transaction_hash} to address: {sender_address}" ) a = self.parent.wallet._get_asset() refund_hash = self.parent.wallet.transfer( sender_address, amount=amount, asset=f"{a.code}:{a.issuer}" ) self.extra_paid = False j.logger.info( f"extra amount: {amount} of transaction {transaction.transaction_hash} refunded successfully in transaction: {refund_hash} to address: {sender_address}" ) except Exception as e: j.logger.critical( f"failed to refund extra amount {amount} for payment: {self.parent.payment_id} due to error: {str(e)}" ) self.parent.save() return self.extra_paidAncestors
- Base
 - types.SimpleNamespace
 
Instance variables
var extra_paid- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var success- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var transactions- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) 
Methods
def refund_extra(self)- 
Expand source code
def refund_extra(self): if self.extra_paid and self.parent.refund_extra: for transaction in self.transactions: if transaction.success: trans_amount = transaction.get_amount(self.parent.wallet) diff = float(trans_amount) - self.parent.amount if diff <= TRANSACTION_FEES: self.extra_paid = False break sender_address = self.parent.wallet.get_sender_wallet_address(transaction.transaction_hash) amount = round(diff - TRANSACTION_FEES, 6) try: j.logger.info( f"refunding extra amount: {amount} of transaction {transaction.transaction_hash} to address: {sender_address}" ) a = self.parent.wallet._get_asset() refund_hash = self.parent.wallet.transfer( sender_address, amount=amount, asset=f"{a.code}:{a.issuer}" ) self.extra_paid = False j.logger.info( f"extra amount: {amount} of transaction {transaction.transaction_hash} refunded successfully in transaction: {refund_hash} to address: {sender_address}" ) except Exception as e: j.logger.critical( f"failed to refund extra amount {amount} for payment: {self.parent.payment_id} due to error: {str(e)}" ) self.parent.save() return self.extra_paid 
Inherited members
 class PaymentTransaction (parent_=None, instance_name_=None, **values)- 
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)Args
parent_:Base, optional- parent instance. Defaults to None.
 instance_name_:str, optional- instance name. Defaults to None.
 **values- any given field values to initiate the instance with
 
Expand source code
class PaymentTransaction(Base): transaction_hash = fields.String(required=True) transaction_refund = fields.Object(PaymentTransactionRefund) success = fields.Boolean(default=False) def refund(self, wallet): if self.transaction_refund.success: return True try: amount = round(self.get_amount(wallet) - Decimal(TRANSACTION_FEES), 6) if amount < 0: self.transaction_refund.success = True else: a = wallet._get_asset() sender_address = wallet.get_sender_wallet_address(self.transaction_hash) j.logger.info( f"refunding transaction: {self.transaction_hash} with amount: {amount} to address: {sender_address}" ) self.transaction_refund.transaction_hash = wallet.transfer( sender_address, amount=amount, asset=f"{a.code}:{a.issuer}" ) self.transaction_refund.success = True j.logger.info( f"transaction: {self.transaction_hash} refunded successfully with amount: {amount} to address: {sender_address} in transaction: {self.transaction_refund.transaction_hash}" ) except Exception as e: j.logger.critical(f"failed to refund transaction: {self.transaction_hash} due to error: {str(e)}") return self.transaction_refund.success def get_amount(self, wallet): try: effects = wallet.get_transaction_effects(self.transaction_hash) except Exception as e: j.logger.warning(f"failed to get transaction effects of hash {self.transaction_hash} due to error {str(e)}") raise e trans_amount = 0 for effect in effects: if effect.asset_code != "TFT": continue trans_amount += effect.amount return trans_amountAncestors
- Base
 - types.SimpleNamespace
 
Instance variables
var success- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var transaction_hash- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var transaction_refund- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) 
Methods
def get_amount(self, wallet)- 
Expand source code
def get_amount(self, wallet): try: effects = wallet.get_transaction_effects(self.transaction_hash) except Exception as e: j.logger.warning(f"failed to get transaction effects of hash {self.transaction_hash} due to error {str(e)}") raise e trans_amount = 0 for effect in effects: if effect.asset_code != "TFT": continue trans_amount += effect.amount return trans_amount def refund(self, wallet)- 
Expand source code
def refund(self, wallet): if self.transaction_refund.success: return True try: amount = round(self.get_amount(wallet) - Decimal(TRANSACTION_FEES), 6) if amount < 0: self.transaction_refund.success = True else: a = wallet._get_asset() sender_address = wallet.get_sender_wallet_address(self.transaction_hash) j.logger.info( f"refunding transaction: {self.transaction_hash} with amount: {amount} to address: {sender_address}" ) self.transaction_refund.transaction_hash = wallet.transfer( sender_address, amount=amount, asset=f"{a.code}:{a.issuer}" ) self.transaction_refund.success = True j.logger.info( f"transaction: {self.transaction_hash} refunded successfully with amount: {amount} to address: {sender_address} in transaction: {self.transaction_refund.transaction_hash}" ) except Exception as e: j.logger.critical(f"failed to refund transaction: {self.transaction_hash} due to error: {str(e)}") return self.transaction_refund.success 
Inherited members
 class PaymentTransactionRefund (parent_=None, instance_name_=None, **values)- 
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)Args
parent_:Base, optional- parent instance. Defaults to None.
 instance_name_:str, optional- instance name. Defaults to None.
 **values- any given field values to initiate the instance with
 
Expand source code
class PaymentTransactionRefund(Base): refund_transaction_hash = fields.String() success = fields.Boolean(default=False)Ancestors
- Base
 - types.SimpleNamespace
 
Instance variables
var refund_transaction_hash- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var success- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) 
Inherited members
 class RefundFactory (type_, name_=None, parent_instance_=None, parent_factory_=None)- 
Stored factories are a custom type of
Factory, which uses current configured store backend to store all instance configurations.get a new stored factory given the type to create and store instances for.
Any factory can have a name, parent
Baseinstance and a parent factory.Once a stored factory is created, it tries to lazy-load all current configuration for given
type_.Args
type_:BaseBaseclass typename_:str, optional- factory name. Defaults to None.
 parent_instance_:Base, optional- a parent 
Baseinstance. Defaults to None. parent_factory_:Factory, optional- a parent 
Factory. Defaults to None. 
Expand source code
class RefundFactory(StoredFactory): def list_active_requests(self): _, _, refunds = self.find_many(success=False) return refundsAncestors
Subclasses
- jumpscale.core.base.factory.RefundFactory
 
Methods
def list_active_requests(self)- 
Expand source code
def list_active_requests(self): _, _, refunds = self.find_many(success=False) return refunds 
Inherited members
 class RefundRequest (parent_=None, instance_name_=None, **values)- 
A simple attribute-based namespace.
SimpleNamespace(**kwargs)
base class implementation for any class with fields which supports getting/setting raw data for any instance fields.
any instance can have an optional name and a parent.
class Person(Base): name = fields.String() age = fields.Float() p = Person(name="ahmed", age="19") print(p.name, p.age)Args
parent_:Base, optional- parent instance. Defaults to None.
 instance_name_:str, optional- instance name. Defaults to None.
 **values- any given field values to initiate the instance with
 
Expand source code
class RefundRequest(Base): payment_id = fields.String(required=True) success = fields.Boolean(default=False) refund_transaction_hash = fields.String() last_tried = fields.DateTime() amount = fields.Float(default=-1) def apply(self): payment = PAYMENT_FACTORY.find_by_id(self.payment_id) if not payment.is_finished(): j.logger.warning(f"can't refund active payment {self.payment_id}") return False self.last_tried = datetime.datetime.utcnow() amount = payment.amount # check if refund extra is False. then amount should be same as successful transaction in case of extra was paid but not refunded automatically sender_address = None for transaction in payment.result.transactions: if transaction.success: sender_address = payment.wallet.get_sender_wallet_address(transaction.transaction_hash) if not payment.refund_extra: amount = float(transaction.get_amount(payment.wallet)) # if a specific amount was specified by the refund request if self.amount > 0: amount = self.amount if amount <= TRANSACTION_FEES or not sender_address: self.success = True else: try: a = payment.wallet._get_asset() self.refund_transaction_hash = payment.wallet.transfer( sender_address, amount=round(amount - TRANSACTION_FEES, 6), asset=f"{a.code}:{a.issuer}" ) self.success = True j.logger.info( f"refund request successful for payment: {self.payment_id} amount: {amount} to address: {sender_address} in transaction: {self.refund_transaction_hash}" ) except Exception as e: j.logger.critical(f"failed to apply refund request for payment {self.payment_id} due to error {str(e)}") self.save() return self.successAncestors
- Base
 - types.SimpleNamespace
 
Instance variables
var amount- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var last_tried- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var payment_id- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var refund_transaction_hash- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) var success- 
getter method this property
will call
_get_value, which would if the value is already defined and will get the default value if notReturns
any- the field value
 
Expand source code
def getter(self): """ getter method this property will call `_get_value`, which would if the value is already defined and will get the default value if not Returns: any: the field value """ return self._get_value(name, field) 
Methods
def apply(self)- 
Expand source code
def apply(self): payment = PAYMENT_FACTORY.find_by_id(self.payment_id) if not payment.is_finished(): j.logger.warning(f"can't refund active payment {self.payment_id}") return False self.last_tried = datetime.datetime.utcnow() amount = payment.amount # check if refund extra is False. then amount should be same as successful transaction in case of extra was paid but not refunded automatically sender_address = None for transaction in payment.result.transactions: if transaction.success: sender_address = payment.wallet.get_sender_wallet_address(transaction.transaction_hash) if not payment.refund_extra: amount = float(transaction.get_amount(payment.wallet)) # if a specific amount was specified by the refund request if self.amount > 0: amount = self.amount if amount <= TRANSACTION_FEES or not sender_address: self.success = True else: try: a = payment.wallet._get_asset() self.refund_transaction_hash = payment.wallet.transfer( sender_address, amount=round(amount - TRANSACTION_FEES, 6), asset=f"{a.code}:{a.issuer}" ) self.success = True j.logger.info( f"refund request successful for payment: {self.payment_id} amount: {amount} to address: {sender_address} in transaction: {self.refund_transaction_hash}" ) except Exception as e: j.logger.critical(f"failed to apply refund request for payment {self.payment_id} due to error {str(e)}") self.save() return self.success 
Inherited members