def process_payment_accounting_report(self, report): method = report.paymentmethod pm = method.get_implementation() sio = io.StringIO(report.contents) reader = csv.DictReader(sio, delimiter=',') for l in reader: # SentForSettle is what we call capture, so we track that # Settled is when we actually receive the money # Changes in Sep 2015 means Settled is sometimes SettledBulk # Everything else we ignore if l['Record Type'] == 'SentForSettle' or l['Record Type'] == 'Settled' or l['Record Type'] == 'SettledBulk': # Find the actual payment pspref = l['Psp Reference'] bookdate = l['Booking Date'] try: trans = TransactionStatus.objects.get(pspReference=pspref, paymentmethod=method) except TransactionStatus.DoesNotExist: # Yes, for now we rollback the whole processing of this one raise Exception('Transaction %s not found!' % pspref) if l['Record Type'] == 'SentForSettle': # If this is a POS transaction, it typically received a # separate CAPTURE notification, in which case the capture # date is already set. But if not, we'll set it to the # sent for settle date. if not trans.capturedat: trans.capturedat = bookdate trans.method = l['Payment Method'] trans.save() AdyenLog(message='Transaction %s captured at %s' % (pspref, bookdate), error=False, paymentmethod=method).save() if self.verbose: self.stdout.write("Sent for settle on {0}".format(pspref)) elif l['Record Type'] in ('Settled', 'SettledBulk'): if trans.settledat is not None: # Transaction already settled. But we might be reprocessing # the report, so verify if the previously settled one is # *identical*. if trans.settledamount == Decimal(l['Main Amount']).quantize(Decimal('0.01')): self.stderr.write("Transaction {0} already settled at {2}, ignoring (NOT creating accounting record)!".format(pspref, trans.settledat)) continue else: raise CommandError('Transaction {0} settled more than once?!'.format(pspref)) if not trans.capturedat: trans.capturedat = bookdate trans.settledat = bookdate trans.settledamount = Decimal(l['Main Amount']).quantize(Decimal('0.01')) trans.save() if self.verbose: self.stdout.write("Settled {0}, total amount {1}".format(pspref, trans.settledamount)) AdyenLog(message='Transaction %s settled at %s' % (pspref, bookdate), error=False, paymentmethod=method).save() # Settled transactions create a booking entry accstr = "Adyen settlement %s" % pspref accrows = [ (pm.config('accounting_authorized'), accstr, -trans.amount, None), (pm.config('accounting_payable'), accstr, trans.settledamount, None), (pm.config('accounting_fee'), accstr, trans.amount - trans.settledamount, trans.accounting_object), ] create_accounting_entry(accrows, False)
def process_reports(self): # Process all downloaded but unprocessed reports for report in Report.objects.filter(downloadedat__isnull=False, processedat=None).order_by('downloadedat'): try: with transaction.atomic(): if self.verbose: self.stdout.write("Processing {0}".format(report.url)) # To know what to do, we look at the filename of the report URL filename = report.url.split('/')[-1] if filename.startswith('payments_accounting_report_'): self.process_payment_accounting_report(report) elif filename.startswith('received_payments_report'): self.process_received_payments_report(report) elif filename.startswith('settlement_detail_report_batch_'): self.process_settlement_detail_report_batch(report) else: raise CommandError('Unknown report type in file "{0}"'.format(filename)) # If successful, flag as processed and add the log report.processedat = timezone.now() report.save() AdyenLog(message='Processed report %s' % report.url, error=False, paymentmethod=report.paymentmethod).save() except Exception as ex: self.stderr.write("Failed to process report {0}: {1}".format(report.url, ex)) AdyenLog(message='Failed to process report %s: %s' % (report.url, ex), error=True, paymentmethod=report.paymentmethod).save()
def handle(self, *args, **options): with transaction.atomic(): try: rawnotification = RawNotification.objects.get(pk=options['id']) except RawNotification.DoesNotExist: raise CommandError("Notification {0} not found.".format( options['id'])) if rawnotification.confirmed: raise CommandError( "Notification {0} is already processed.".format( options['id'])) # Rebuild a POST dictionary with the contents of this request POST = QueryDict(rawnotification.contents, "utf8") AdyenLog(pspReference=rawnotification.id, message='Reprocessing RAW notification id %s' % rawnotification.id, error=False, paymentmethod=rawnotification.paymentmethod).save() process_raw_adyen_notification(rawnotification, POST) self.stdout.write( "Completed reprocessing raw notification {0}".format( rawnotification.id))
def download_reports(self): # Download all currently pending reports (that we can) for report in Report.objects.filter( downloadedat=None).order_by('receivedat'): pm = report.paymentmethod.get_implementation() try: with transaction.atomic(): if self.verbose: self.stdout.write("Downloading {0}".format(report.url)) resp = requests.get(report.url, auth=HTTPBasicAuth( pm.config('report_user'), pm.config('report_password'))) if resp.status_code != 200: self.stderr.write( "Downloaded report {0} and got status code {1}. Not storing, will try again." .format(report.url, resp.status_code)) elif len(resp.text) == 0: self.stderr.write( "Downloaded report {0} and got zero bytes (no header). Not storing, will try again." .format(report.url)) else: report.downloadedat = datetime.now() report.contents = resp.text report.save() AdyenLog(message='Downloaded report {0}'.format( report.url), error=False, paymentmethod=report.paymentmethod).save() except Exception as ex: self.stderr.write("Failed to download report {0}: {1}".format( report.url, ex)) # This might fail again if we had a db problem, but it should be OK as long as it # was just a download issue which is most likely. AdyenLog(message='Failed to download report %s: %s' % (report.url, ex), error=True, paymentmethod=report.paymentmethod).save()
def handle(self, *args, **options): with transaction.atomic(): try: notification = Notification.objects.get(pspReference=options['pspreference']) except Notification.DoesNotExist: raise CommandError("Notification {0} does not exist.".format(options['pspreference'])) AdyenLog(pspReference=notification.pspReference, message='Reprocessing notification id {0}'.format(notification.id), error=False, paymentmethod=notification.rawnotification.paymentmethod).save() process_one_notification(notification) self.stdout.write("Completed reprocessing notification {0}.".format(notification.pspReference))
def download_reports(self): # Download all currently pending reports (that we can) for report in Report.objects.filter( downloadedat=None).order_by('receivedat'): pm = report.paymentmethod.get_implementation() if not report.url.endswith('.csv'): with transaction.atomic(): report.downloadedat = timezone.now() report.processedat = timezone.now() report.save() if report.url.endswith('.pdf') or report.url.endswith( '.xlsx'): # For known file-types, just log it and not as an error. AdyenLog( message= "Report {} is not of type csv, ignoring but flagging as downloaded and processed" .format(report.url), error=False, paymentmethod=report.paymentmethod).save() else: # For unknown types, log as an error in case this is something broken. AdyenLog( message= "Report {} is of unknown type, ignoring but flagging as downloaded and processed" .format(report.url), error=True, paymentmethod=report.paymentmethod).save() continue # Now that we know it's a CSV, download the contents of the report try: with transaction.atomic(): if self.verbose: self.stdout.write("Downloading {0}".format(report.url)) resp = requests.get(report.url, auth=HTTPBasicAuth( pm.config('report_user'), pm.config('report_password'))) if resp.status_code != 200: self.stderr.write( "Downloaded report {0} and got status code {1}. Not storing, will try again." .format(report.url, resp.status_code)) elif len(resp.text) == 0: self.stderr.write( "Downloaded report {0} and got zero bytes (no header). Not storing, will try again." .format(report.url)) else: report.downloadedat = timezone.now() report.contents = resp.text report.save() AdyenLog(message='Downloaded report {0}'.format( report.url), error=False, paymentmethod=report.paymentmethod).save() except Exception as ex: self.stderr.write("Failed to download report {0}: {1}".format( report.url, ex)) # This might fail again if we had a db problem, but it should be OK as long as it # was just a download issue which is most likely. AdyenLog(message='Failed to download report %s: %s' % (report.url, ex), error=True, paymentmethod=report.paymentmethod).save()