feat: add WithdrawCalc method — withdrawal amount calculation - #42
Open
Flummy1 wants to merge 1 commit into
Open
feat: add WithdrawCalc method — withdrawal amount calculation#42Flummy1 wants to merge 1 commit into
Flummy1 wants to merge 1 commit into
Conversation
Add support for the withdrawal amount calculation endpoint (https://funpay.com/withdraw/calc), which FunPay uses to convert between the amount debited from the balance and the amount credited to the wallet. Exactly one of `amount_int` / `amount_ext` must be passed: the one that is omitted is the one FunPay calculates and returns. New files: - types/withdraw.py: WithdrawCalcResult pydantic model - methods/withdraw_calc.py: WithdrawCalc method Also adds the `Bot.calc_withdraw()` shortcut. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Контекст
FunPay считает сумму вывода на стороне сервера: пользователь вводит одну из двух сумм,
вторую возвращает эндпоинт
POST https://funpay.com/withdraw/calc. В движке этой возможностине было — посчитать, сколько реально придёт на карту после комиссии (или сколько списать с
баланса, чтобы получить нужную сумму), было нечем.
Механика взята из обработчика формы вывода в
app.bundle.js(функция инициализации.withdraw-box):Ключевое: поле суммы, которое пользователь не редактирует, помечается классом
slaveиудаляется из тела запроса; именно его сайт и получает в ответе. Логика симметрична —
отправил
amount_ext, получилamount_int, и наоборот.Смысл величин:
amount_int— сумма, списываемая с баланса FunPay;amount_ext— сумма, зачисляемая на карту / кошелёк (комиссия уже вычтена).csrf_tokenотдельно передавать не нужно — его подставляет сессия(
AioHttpSession.make_request).Что добавлено
funpaybotengine/types/withdraw.pyWithdrawCalcResult— модель ответа (новый)funpaybotengine/methods/withdraw_calc.pyWithdrawCalc— методwithdraw/calc(новый)funpaybotengine/types/__init__.py,funpaybotengine/methods/__init__.pyfunpaybotengine/client/bot.pyBot.calc_withdraw()Метод построен по образцу уже существующих
CalcLots/CalcChips:POST, заголовокX-Requested-With: XMLHttpRequest,json.loadsвparse_result, pydantic-модель в__model_to_build__.Инвариант «ровно одна из сумм» держит
model_validator(mode='after')— вторая не попадает втело запроса вообще, как и в вебе. Передать обе или ни одной нельзя:
ValidationErrorдо обращения к сети, а не пустой ответ после.
Тело запроса собирается callable-функцией
make_data(как вGetTransactions), поэтому оновсегда соответствует текущему состоянию модели:
{'preview': '1', 'currency_id': 'rub', 'ext_currency_id': 'card_rub', 'wallet': '2202...', 'amount_ext': 500000.0}WithdrawCalcResultтерпим к формату: оба поля опциональны (в ответе всегда ровно одно),строковые суммы нормализуются — обычный и неразрывный пробел как разделитель разрядов,
запятая как десятичный разделитель, пустая строка →
None.Использование
Границы изменения
Осознанно не входит в этот PR:
error/twofactor_error) — нуженform[action]со страницы/account/balance, в бандле он не зашит;ext_currency_id, комиссий и сохранённых кошельков — они лежат в.withdraw-box[data-data], аTransactionsPageParserэтот блок не разбирает. Это задача дляfunpayparsers;ext_currency_id == 'fps') — имя поля в бандле не видно (в ответеsubmit'а оно фигурирует как
fps_bank_name).Поэтому
currency_id/ext_currency_idтипизированы какstr, а не enum: маппинг наPaymentMethodизfunpayparsersсовпадает дляcard_rub/fps, но для WebMoney не проверен,а гадать на публичном API не стоит.
Из-за
validate_assignment=Trueу уже созданногоWithdrawCalcнельзя переключить«ведущее» поле присваиванием — под каждый расчёт создаётся новый объект, ровно как у
CalcLots/CalcChips.Обратная совместимость
Изменений в существующем поведении нет — только новые сущности и один новый метод
Bot.Проверки
Сборка тела запроса и разбор ответа проверены локально на данных из реального сетевого лога
/withdraw/calc; живых запросов к FunPay в рамках PR не выполнялось.