def __init__(self, *args, **kwargs): super(Transaction, self).__init__(*args, **kwargs) # Gonna do_fetch = False here. We don't want to fetch every object every time we run Transaction.objects.all() in the shell # And we won't have control over fetching when we do a filter. if self.reference_id == None: self._core_remote_object = CoreTransaction( feefighters=settings.SAMURAI_CREDENTIALS, payment_method=self.payment_method._core_remote_object, processor_token=self.processor_token, do_fetch=False, ) else: self._core_remote_object = CoreTransaction( feefighters=settings.SAMURAI_CREDENTIALS, reference_id=self.reference_id, processor_token=self.processor_token, do_fetch=False, ) # exclude here since overwriting before fetch could wipe out what's from the DB # all we want are things that aren't in the database. Even if it's a new transaction and the values are None, we want the attributes there. self._get_fields_from_core( exclude=[ "transaction_token", "reference_id", "transaction_type", "amount", "currency_code", "created_at", "processor_success", ] ) self._set_fields_into_core()
class Transaction(models.Model, RemoteObject): transaction_token = models.CharField(max_length=100, editable=False) processor_token = models.CharField(max_length=100, editable=False) reference_id = models.CharField(unique=True, max_length=100, editable=False) payment_method = models.ForeignKey(PaymentMethod, editable=False) transaction_type = models.CharField(max_length=20, editable=False) amount = models.CharField( max_length=10, editable=False, blank=True, default="" ) # null and blank to avoid migration currency_code = models.CharField(max_length=10, editable=False, blank=True, default="") created_at = models.DateTimeField(editable=False, null=True, blank=True, default=None) processor_success = models.NullBooleanField(editable=False, null=True, blank=True, default=None) def __init__(self, *args, **kwargs): super(Transaction, self).__init__(*args, **kwargs) # Gonna do_fetch = False here. We don't want to fetch every object every time we run Transaction.objects.all() in the shell # And we won't have control over fetching when we do a filter. if self.reference_id == None: self._core_remote_object = CoreTransaction( feefighters=settings.SAMURAI_CREDENTIALS, payment_method=self.payment_method._core_remote_object, processor_token=self.processor_token, do_fetch=False, ) else: self._core_remote_object = CoreTransaction( feefighters=settings.SAMURAI_CREDENTIALS, reference_id=self.reference_id, processor_token=self.processor_token, do_fetch=False, ) # exclude here since overwriting before fetch could wipe out what's from the DB # all we want are things that aren't in the database. Even if it's a new transaction and the values are None, we want the attributes there. self._get_fields_from_core( exclude=[ "transaction_token", "reference_id", "transaction_type", "amount", "currency_code", "created_at", "processor_success", ] ) self._set_fields_into_core() def _get_fields_from_core(self, exclude=[]): for field_name in ( set(self._core_remote_object.field_names + ["populated"]) - set(["payment_method", "processor_token"]) - set(exclude) ): setattr(self, field_name, getattr(self._core_remote_object, field_name)) # self.payment_method should really always be set, but I'm avoiding unnecessary errors if I made a mistake somewhere if self.payment_method and self._core_remote_object.payment_method: self.payment_method._core_remote_object = self._core_remote_object.payment_method def _set_fields_into_core(self): for field_name in set(self._core_remote_object.field_names) - set(["payment_method", "processor_token"]): setattr(self._core_remote_object, field_name, getattr(self, field_name)) self._core_remote_object.payment_method = self.payment_method._core_remote_object def _save_new_transaction(self, new_transaction_core): new_transaction = Transaction( transaction_token=new_transaction_core.transaction_token, reference_id=new_transaction_core.reference_id, payment_method=self.payment_method, transaction_type=new_transaction_core.transaction_type, amount=new_transaction_core.amount, currency_code=new_transaction_core.currency_code, created_at=new_transaction_core.created_at, processor_success=new_transaction_core.processor_success, ) try: new_transaction.full_clean() new_transaction.save() except: self._set_payment_method_last_transaction_error(True) return None else: self._set_payment_method_last_transaction_error(False) new_transaction._core_remote_object = new_transaction_core new_transaction._get_fields_from_core() return new_transaction def _set_payment_method_last_transaction_error(self, error): payment_method = self.payment_method payment_method.last_transaction_error = error payment_method.save() def purchase(self, amount, currency_code, billing_reference, customer_reference): self._set_fields_into_core() result = self._core_remote_object.purchase(amount, currency_code, billing_reference, customer_reference) self._get_fields_from_core() try: self.full_clean() except: self._set_payment_method_last_transaction_error(True) return False if self.reference_id != "": self.save() self._set_payment_method_last_transaction_error(not result) return result def authorize(self, amount, currency_code, billing_reference, customer_reference): self._set_fields_into_core() result = self._core_remote_object.authorize(amount, currency_code, billing_reference, customer_reference) self._get_fields_from_core() try: self.full_clean() except: return False self.save() self._set_payment_method_last_transaction_error(not result) return result def capture(self, amount): self._set_fields_into_core() new_transaction_core = self._core_remote_object.capture(amount) return self._save_new_transaction(new_transaction_core) def void(self): self._set_fields_into_core() new_transaction_core = self._core_remote_object.void() return self._save_new_transaction(new_transaction_core) def credit(self, amount): self._set_fields_into_core() new_transaction_core = self._core_remote_object.credit(amount) return self._save_new_transaction(new_transaction_core) def fetch(self): self._set_fields_into_core() result = self._core_remote_object.fetch() self._get_fields_from_core() return result