#!/usr/bin/env python3 """Single HissPay payout request. Preview by default; no automatic retries.""" import argparse, json, os, stat, sys from pathlib import Path os.environ.setdefault('HISSPAY_GATEWAY', 'https://sandbox-api.hisspay.com') import client ACTIONS={'apply':'payout','query':'payout_query','balance':'balance'} def codes_optional(b): return b.get('payCode')=='CARD' and (b.get('product'),b.get('currency')) in ( ('USD-PAYPLUS-PAYOUT','USD'),('USD-LOCAL-PAYOUT','USD'),('AUD-LOCAL-PAYOUT','AUD')) def load(path, action): p=Path(path) if p.is_symlink() or not stat.S_ISREG(p.stat().st_mode) or p.stat().st_mode & 0o077: raise ValueError('Use a private regular JSON file, chmod 600') b=json.loads(p.read_text()) if not isinstance(b,dict) or any(not isinstance(v,str) for v in b.values()): raise ValueError('Use flat string fields, including amount and extra') if action=='balance': return {'currency':b['currency']} if action=='query': return {'merchantOrderNo':b['merchantOrderNo']} required=('merchantOrderNo','amount','currency','product','accountName','account','phone','email','payCode','notifyUrl') if not codes_optional(b): required += ('bizCode','branchCode') if any(not b.get(k) for k in required): raise ValueError('Missing payout field') if b['payCode']=='CARD' and not b['account'].startswith('SANDBOX-'): extra=json.loads(b.get('extra','{}')) if set(extra)!={'beneficiary_id','card_valid'} or type(extra['beneficiary_id']) is not int or extra['beneficiary_id']<=0: raise ValueError('Set the platform-bound beneficiary and expiry') return b def validate_target(body,gateway): if body.get('account','').startswith('SANDBOX-') and gateway!='https://sandbox-api.hisspay.com': raise ValueError('Synthetic payout recipients require sandbox') def main(): p=argparse.ArgumentParser(description=__doc__);p.add_argument('action',choices=ACTIONS);p.add_argument('file');p.add_argument('--send',action='store_true');a=p.parse_args() try: if client.GATEWAY not in ('https://sandbox-api.hisspay.com','https://transaction.hisspay.com'): raise ValueError('Unrecognized gateway') body=load(a.file,a.action) validate_target(body,client.GATEWAY) if not a.send: print(json.dumps({'preview':True,'gateway':client.GATEWAY,'path':client.PATHS[ACTIONS[a.action]],'fields':list(body),'note':'No request sent; recipient data omitted'}));return 0 app=os.environ['HISSPAY_APP_ID'];secret=os.environ['HISSPAY_APP_SECRET'] status,result=client.request(ACTIONS[a.action],body,app,secret) print(json.dumps({'http':status,'response':result},ensure_ascii=False));return 0 if status==200 and result.get('code')==0 else 1 except (ValueError,KeyError,OSError): print('NOT_CONFIRMED: check private configuration; if submission may have occurred, query the original merchantOrderNo.',file=sys.stderr);return 1 if __name__=='__main__':sys.exit(main())