示例#1
0
 def __init__(self):
     self.paypal = PayPalClient(None)
 def __init__(self):
     self.paypal = PayPalClient(None)
示例#3
0
class PayoutEngine(object):
    def __init__(self):
        self.paypal = PayPalClient(None)

    def _get_reports(self):
        headers = {
            'content-type': 'application/json',
            'X-Nick-Name': settings.STORE_NAME,
            'X-Roles': settings.ADMIN_ROLE,
            'X-Email': settings.WSTOREMAIL
        }

        data = {
            'aggregatorId': None,
            'providerId': None,
            'productClass': None,
            'onlyPaid': "true"
        }

        # Make request
        url = settings.RSS
        if not url.endswith('/'):
            url += '/'

        url += 'rss/settlement/reports'

        response = requests.get(url, params=data, headers=headers)

        if response.status_code != 200:
            print("Error retrieving reports: {}".format(response.reason))
            return []

        return response.json()

    def _process_reports(self, reports):
        new_reports = defaultdict(lambda: defaultdict(list))
        # Divide by currency
        for report in reports:
            if report['paid']:
                continue
            semipaid = None
            try:
                semipaid = ReportSemiPaid.objects.get(report=report['id'])
            except ObjectDoesNotExist:
                pass

            currency = report['currency']
            usermail = User.objects.get(
                username=report['ownerProviderId']).email

            if semipaid is None or usermail not in semipaid.success:
                new_reports[currency][usermail].append(
                    (report['ownerValue'], report['id']))

            for stake in report['stakeholders']:
                stakemail = User.objects.get(
                    username=stake['stakeholderId']).email

                if semipaid is None or stakemail not in semipaid.success:
                    new_reports[currency][stakemail].append(
                        (stake['modelValue'], report['id']))

        return new_reports

    def _process_payouts(self, data):
        db = get_database_connection()
        reference = "__payout__engine__context__lock__"
        # Uses an atomic operation to get and set the _lock value in the purchase
        # document
        pre_value = db.wstore_payout.find_one_and_update(
            {'_id': reference}, {'$set': {
                '_lock': True
            }})

        # If no reference exists, create it
        if pre_value is None:
            db.wstore_payout.insert_one({'_id': reference, '_lock': False})
            pre_value = db.wstore_payout.find_one_and_update(
                {'_id': reference}, {'$set': {
                    '_lock': True
                }})

        # If the value of _lock before setting it to true was true, means
        # that the time out function has acquired it previously so the
        # view ends
        if '_lock' in pre_value and pre_value['_lock']:
            raise PayoutError('There is a payout running.')

        payments = []
        context = Context.objects.all()[0]
        current_id = context.payouts_n

        for currency, users in data.items():
            payments.append([])
            for user, values in users.items():
                for value, report in values:
                    sender_id = '{}_{}'.format(report, current_id)
                    payment = {
                        'recipient_type': 'EMAIL',
                        'amount': {
                            'value': "{0:.2f}".format(round(Decimal(value),
                                                            2)),
                            'currency': currency
                        },
                        'receiver': user,
                        'sender_item_id': sender_id
                    }
                    current_id += 1
                    payments[-1].append(payment)

        context.payouts_n = current_id
        context.save()

        # _lock is set to false
        db.wstore_payout.find_one_and_update({'_id': reference},
                                             {'$set': {
                                                 '_lock': False
                                             }})

        return [self.paypal.batch_payout(paybatch) for paybatch in payments]

    def process_reports(self, reports):
        processed = self._process_reports(reports)
        payouts = self._process_payouts(processed)
        to_watch = []

        for payout, created in payouts:
            if not created:
                # Full error, not even said the semipaid because it didn't failed some transaction
                print("Error, batch id: {}".format(
                    payout['sender_batch_header']['sender_batch_id']))  # Log
                continue
            payout_id = payout['batch_header']['payout_batch_id']
            status = payout['batch_header']['batch_status']
            rpayout = ReportsPayout(reports=reports,
                                    payout_id=payout_id,
                                    status=status)
            rpayout.save()

            to_watch.append(payout)

        if len(to_watch) > 0:
            watcher = PayoutWatcher(to_watch, reports)
            watcher.start()

    def process_unpaid(self):
        reports = self._get_reports()
        self.process_reports(reports)
class PayoutEngine(object):
    def __init__(self):
        self.paypal = PayPalClient(None)

    def _get_reports(self):
        headers = {
            "content-type": "application/json",
            "X-Nick-Name": settings.STORE_NAME,
            "X-Roles": "provider",
            "X-Email": settings.WSTOREMAIL,
        }

        data = {"aggregatorId": None, "providerId": None, "productClass": None, "onlyPaid": "true"}

        # Make request
        url = settings.RSS
        if not url.endswith("/"):
            url += "/"

        url += "rss/settlement/reports"

        response = requests.get(url, params=data, headers=headers)

        if response.status_code != 200:
            print("Error retrieving reports: {}".format(response.reason))
            return []

        return response.json()

    def _process_reports(self, reports):
        new_reports = defaultdict(lambda: defaultdict(list))
        # Divide by currency
        for report in reports:
            if report["paid"]:
                continue
            semipaid = None
            try:
                semipaid = ReportSemiPaid.objects.get(report=report["id"])
            except ObjectDoesNotExist:
                pass

            currency = report["currency"]
            usermail = User.objects.get(username=report["ownerProviderId"]).email

            if semipaid is None or usermail not in semipaid.success:
                new_reports[currency][usermail].append((report["ownerValue"], report["id"]))

            for stake in report["stakeholders"]:
                stakemail = User.objects.get(username=stake["stakeholderId"]).email

                if semipaid is None or stakemail not in semipaid.success:
                    new_reports[currency][stakemail].append((stake["modelValue"], report["id"]))

        return new_reports

    def _process_payouts(self, data):
        db = get_database_connection()
        reference = "__payout__engine__context__lock__"
        # Uses an atomic operation to get and set the _lock value in the purchase
        # document
        pre_value = db.wstore_payout.find_one_and_update({"_id": reference}, {"$set": {"_lock": True}})

        # If no reference exists, create it
        if pre_value is None:
            db.wstore_payout.insert_one({"_id": reference, "_lock": False})
            pre_value = db.wstore_payout.find_one_and_update({"_id": reference}, {"$set": {"_lock": True}})

        # If the value of _lock before setting it to true was true, means
        # that the time out function has acquired it previously so the
        # view ends
        if "_lock" in pre_value and pre_value["_lock"]:
            raise PayoutError("There is a payout running.")

        payments = []
        context = Context.objects.all()[0]
        current_id = context.payouts_n

        for currency, users in data.items():
            payments.append([])
            for user, values in users.items():
                for value, report in values:
                    sender_id = "{}_{}".format(report, current_id)
                    payment = {
                        "recipient_type": "EMAIL",
                        "amount": {"value": "{0:.2f}".format(round(Decimal(value), 2)), "currency": currency},
                        "receiver": user,
                        "sender_item_id": sender_id,
                    }
                    current_id += 1
                    payments[-1].append(payment)

        context.payouts_n = current_id
        context.save()

        # _lock is set to false
        db.wstore_payout.find_one_and_update({"_id": reference}, {"$set": {"_lock": False}})

        return [self.paypal.batch_payout(paybatch) for paybatch in payments]

    def process_reports(self, reports):
        processed = self._process_reports(reports)
        payouts = self._process_payouts(processed)
        to_watch = []

        for payout, created in payouts:
            if not created:
                # Full error, not even said the semipaid because it didn't failed some transaction
                print("Error, batch id: {}".format(payout["sender_batch_header"]["sender_batch_id"]))  # Log
                continue
            payout_id = payout["batch_header"]["payout_batch_id"]
            status = payout["batch_header"]["batch_status"]
            rpayout = ReportsPayout(reports=reports, payout_id=payout_id, status=status)
            rpayout.save()

            to_watch.append(payout)

        if len(to_watch) > 0:
            watcher = PayoutWatcher(to_watch, reports)
            watcher.start()

    def process_unpaid(self):
        reports = self._get_reports()
        self.process_reports(reports)