PageRenderTime 86ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/sauthorize/schemas.py

https://gitlab.com/superiorthreads/superior-authorize
Python | 457 lines | 368 code | 82 blank | 7 comment | 15 complexity | a722c5d007793592f86c6a4038ce4160 MD5 | raw file
  1. import colander
  2. from datetime import date
  3. from uuid import uuid4
  4. @colander.deferred
  5. def merchant_id(node, kw):
  6. return uuid4().hex[:20]
  7. @colander.deferred
  8. def today(node, kw):
  9. return date.today().isoformat()
  10. class AddressSchema(colander.MappingSchema):
  11. first_name = colander.SchemaNode(colander.String(),
  12. validator=colander.Length(max=50),
  13. missing=colander.drop)
  14. last_name = colander.SchemaNode(colander.String(),
  15. validator=colander.Length(max=50),
  16. missing=colander.drop)
  17. company = colander.SchemaNode(colander.String(),
  18. validator=colander.Length(max=50),
  19. missing=colander.drop)
  20. address = colander.SchemaNode(colander.String(),
  21. validator=colander.Length(max=60),
  22. missing=colander.drop)
  23. city = colander.SchemaNode(colander.String(),
  24. validator=colander.Length(max=40),
  25. missing=colander.drop)
  26. state = colander.SchemaNode(colander.String(),
  27. validator=colander.Length(max=40),
  28. missing=colander.drop)
  29. zip = colander.SchemaNode(colander.String(),
  30. validator=colander.Length(max=20),
  31. missing=colander.drop)
  32. country = colander.SchemaNode(colander.String(),
  33. validator=colander.Length(max=60),
  34. missing=colander.drop)
  35. phone_number = colander.SchemaNode(colander.String(),
  36. validator=colander.Length(max=25),
  37. missing=colander.drop)
  38. fax_number = colander.SchemaNode(colander.String(),
  39. validator=colander.Length(max=25),
  40. missing=colander.drop)
  41. class CreditCardSchema(colander.MappingSchema):
  42. card_number = colander.SchemaNode(colander.String(),
  43. validator=colander.luhnok,
  44. required=True)
  45. expiration_month = colander.SchemaNode(colander.Integer(),
  46. validator=colander.Range(1, 12),
  47. missing=None)
  48. expiration_year = colander.SchemaNode(colander.Integer(),
  49. validator=colander.Range(date.today().year,
  50. date.today().year + 7),
  51. missing=None)
  52. expiration_date = colander.SchemaNode(colander.String(),
  53. validator=colander.Regex(
  54. r'^\d{2}.?(?:\d{4}|\d{2})?$', 'The expiration date is invalid'),
  55. missing=None)
  56. card_code = colander.SchemaNode(colander.String(),
  57. validator=colander.Regex(r'^[0-9]{3,4}$', 'The card code is invalid'),
  58. missing=colander.drop)
  59. @staticmethod
  60. def validator(node, kw):
  61. exp_year = kw['expiration_year']
  62. exp_month = kw['expiration_month']
  63. exp_date = kw['expiration_date']
  64. # We only need exp_date or exp_year and exp_month
  65. if exp_date is None and (exp_year is None and exp_month is None):
  66. raise colander.Invalid(node, 'You must provide a card expiration date')
  67. if exp_date is not None:
  68. exp_month = exp_date[:2]
  69. exp_year = '20' + exp_date[-2:]
  70. elif exp_month is None:
  71. raise colander.Invalid(node, 'You must provide a card expiration month')
  72. elif exp_year is None:
  73. raise colander.Invalid(node, 'You must provide a card expiration year')
  74. if exp_year == date.today().year and exp_month < date.today().month:
  75. raise colander.Invalid(node, 'The credit card has expired')
  76. kw['expiration_year'] = str(exp_year)
  77. kw['expiration_month'] = str(exp_month).zfill(2)
  78. class TrackDataSchema(colander.MappingSchema):
  79. track_1 = colander.SchemaNode(colander.String(),
  80. validator=colander.Regex(
  81. r'^%?B\d{1,19}\^[A-Z /]{2,26}\^(\d|\^){4}(\d|\^){3}.*\??$',
  82. 'Track 1 does not match IATA format'),
  83. missing=colander.drop,
  84. required=None)
  85. track_2 = colander.SchemaNode(colander.String(),
  86. validator=colander.Regex(
  87. r'^;?\d{1,19}=(\d|=){4}(\d|=){3}.*\??$', 'Track 2 does not match ABA format'),
  88. missing=colander.drop,
  89. required=None)
  90. @staticmethod
  91. def validator(node, kw):
  92. track1 = kw.get('track_1', None)
  93. track2 = kw.get('track_2', None)
  94. if track1 is None and track2 is None:
  95. raise colander.Invalid(node, "You must provide at least one track")
  96. if track1:
  97. kw['track_1'] = str(track1).lstrip('%').rstrip('?')
  98. if track2:
  99. kw['track_2'] = str(track2).lstrip(';').rstrip('?')
  100. class RetailSchema(colander.MappingSchema):
  101. market_type = colander.SchemaNode(colander.Integer(),
  102. validator=colander.Range(1, 9),
  103. required=True)
  104. device_type = colander.SchemaNode(colander.Integer(),
  105. validator=colander.Range(1, 9),
  106. required=True)
  107. @staticmethod
  108. def validator(node, kw):
  109. kw['market_type'] = kw.get('market_type', 2)
  110. kw['device_type'] = kw.get('device_type', 7)
  111. class BankAccountSchema(colander.MappingSchema):
  112. account_type = colander.SchemaNode(colander.String(),
  113. validator=colander.OneOf(['checking', 'savings', 'businessChecking']),
  114. missing=colander.drop)
  115. routing_number = colander.SchemaNode(colander.String(),
  116. validator=colander.Regex(r'^[\d+]{9}$', 'The routing number is invalid'),
  117. required=True)
  118. account_number = colander.SchemaNode(colander.String(),
  119. validator=colander.Regex(r'^[\d+]{5,17}$', 'The account number is invalid'),
  120. required=True)
  121. name_on_account = colander.SchemaNode(colander.String(),
  122. validator=colander.Length(max=22),
  123. required=True)
  124. echeck_type = colander.SchemaNode(colander.String(),
  125. validator=colander.OneOf(['ARC', 'BOC', 'CCD', 'PPD', 'TEL', 'WEB']),
  126. missing=colander.drop)
  127. bank_name = colander.SchemaNode(colander.String(),
  128. validator=colander.Length(max=50),
  129. missing=colander.drop)
  130. class CustomerTypeSchema(colander.MappingSchema):
  131. customer_type = colander.SchemaNode(colander.String(),
  132. validator=colander.OneOf(['individual', 'business']),
  133. missing=colander.drop)
  134. class CreateCreditCardSchema(CreditCardSchema, CustomerTypeSchema):
  135. billing = AddressSchema(missing=colander.drop)
  136. class UpdateCreditCardSchema(CreateCreditCardSchema):
  137. card_number = colander.SchemaNode(colander.String(),
  138. validator=colander.Length(min=4),
  139. required=True)
  140. class ValidateCreditCardSchema(colander.MappingSchema):
  141. address_id = colander.SchemaNode(colander.String(),
  142. validator=colander.Length(max=60),
  143. missing=colander.drop)
  144. card_code = colander.SchemaNode(colander.String(),
  145. validator=colander.Regex(
  146. r'^[0-9]{3,4}$', 'The card code is invalid'),
  147. missing=colander.drop)
  148. # A test mode is required for this transaction type. By default, we will
  149. # use 'testMode'
  150. validation_mode = colander.SchemaNode(colander.String(),
  151. validator=colander.OneOf(['liveMode', 'testMode']),
  152. missing='testMode')
  153. class CreateBankAccountSchema(BankAccountSchema, CustomerTypeSchema):
  154. billing = AddressSchema(missing=colander.drop)
  155. class CustomerBaseSchema(colander.MappingSchema):
  156. merchant_id = colander.SchemaNode(colander.String(),
  157. validator=colander.Length(max=20),
  158. missing=merchant_id)
  159. description = colander.SchemaNode(colander.String(),
  160. validator=colander.Length(max=255),
  161. missing=colander.drop)
  162. email = colander.SchemaNode(colander.String(),
  163. validator=colander.Email(),
  164. missing=colander.drop)
  165. class CustomerSchema(AddressSchema):
  166. email = colander.SchemaNode(colander.String(),
  167. validator=colander.Email(),
  168. missing=colander.drop)
  169. customer_id = colander.SchemaNode(colander.String(),
  170. validator=colander.Length(max=20),
  171. missing=colander.drop)
  172. class CreateCustomerSchema(CustomerBaseSchema, CustomerTypeSchema):
  173. # Customer payment method (optional)
  174. credit_card = CreditCardSchema(validator=CreditCardSchema.validator,
  175. missing=colander.drop)
  176. bank_account = BankAccountSchema(validator=BankAccountSchema.validator,
  177. missing=colander.drop)
  178. # Customer address information
  179. billing = AddressSchema(missing=colander.drop)
  180. shipping = AddressSchema(missing=colander.drop)
  181. class AmountItemSchema(colander.MappingSchema):
  182. name = colander.SchemaNode(colander.String(),
  183. validator=colander.Length(max=31),
  184. missing=colander.drop)
  185. description = colander.SchemaNode(colander.String(),
  186. validator=colander.Length(max=255),
  187. missing=colander.drop)
  188. amount = colander.SchemaNode(colander.Decimal('0.01'),
  189. validator=colander.Range(min=0),
  190. missing=colander.drop)
  191. class LineItemSchema(colander.MappingSchema):
  192. item_id = colander.SchemaNode(colander.String(),
  193. validator=colander.Length(max=31),
  194. missing=colander.drop)
  195. name = colander.SchemaNode(colander.String(),
  196. validator=colander.Length(max=31),
  197. missing=colander.drop)
  198. description = colander.SchemaNode(colander.String(),
  199. validator=colander.Length(max=255),
  200. missing=colander.drop)
  201. quantity = colander.SchemaNode(colander.Integer(),
  202. validator=colander.Range(min=0, max=99),
  203. missing=colander.drop)
  204. unit_price = colander.SchemaNode(colander.Decimal('0.01'),
  205. validator=colander.Range(min=0),
  206. missing=colander.drop)
  207. taxable = colander.SchemaNode(colander.Boolean(),
  208. missing=colander.drop)
  209. class LineItemsSchema(colander.SequenceSchema):
  210. line_item = LineItemSchema()
  211. class UserFieldSchema(colander.MappingSchema):
  212. name = colander.SchemaNode(colander.String(),
  213. missing=colander.drop)
  214. value = colander.SchemaNode(colander.String(),
  215. missing=colander.drop)
  216. class UserFieldsSchema(colander.SequenceSchema):
  217. user_field = UserFieldSchema()
  218. class OrderSchema(colander.MappingSchema):
  219. invoice_number = colander.SchemaNode(colander.String(),
  220. validator=colander.Length(max=25),
  221. missing=colander.drop)
  222. description = colander.SchemaNode(colander.String(),
  223. validator=colander.Length(max=255),
  224. missing=colander.drop)
  225. order_number = colander.SchemaNode(colander.String(),
  226. validator=colander.Length(max=25),
  227. missing=colander.drop)
  228. class ExtraOptions(colander.MappingSchema):
  229. duplicate_window = colander.SchemaNode(colander.Integer(),
  230. validator=colander.Range(0, 28800),
  231. missing=colander.drop)
  232. class TransactionBaseSchema(colander.MappingSchema):
  233. line_items = LineItemsSchema(validator=colander.Length(max=30),
  234. missing=colander.drop)
  235. user_fields = UserFieldsSchema(validator=colander.Length(max=30),
  236. missing=colander.drop)
  237. order = OrderSchema(missing=colander.drop)
  238. tax = AmountItemSchema(missing=colander.drop)
  239. duty = AmountItemSchema(missing=colander.drop)
  240. shipping_and_handling = AmountItemSchema(missing=colander.drop)
  241. amount = colander.SchemaNode(colander.Decimal('0.01'),
  242. validator=colander.Range(0, 20000),
  243. required=True)
  244. split_tender_id = colander.SchemaNode(colander.String(),
  245. missing=colander.drop)
  246. tax_exempt = colander.SchemaNode(colander.Boolean(), missing=colander.drop)
  247. customer_ip = colander.SchemaNode(colander.String(),
  248. validator=colander.Length(max=39),
  249. missing=colander.drop)
  250. class CIMBaseSchema(colander.MappingSchema):
  251. customer_id = colander.SchemaNode(colander.String(),
  252. validator=colander.Length(max=60),
  253. required=True)
  254. payment_id = colander.SchemaNode(colander.String(),
  255. validator=colander.Length(max=60),
  256. required=True)
  257. address_id = colander.SchemaNode(colander.String(),
  258. validator=colander.Length(max=60),
  259. missing=colander.drop)
  260. class CIMTransactionSchema(CIMBaseSchema, TransactionBaseSchema):
  261. recurring = colander.SchemaNode(colander.Boolean(),
  262. missing=colander.drop)
  263. card_code = colander.SchemaNode(colander.String(),
  264. validator=colander.Regex(
  265. r'^[0-9]{3,4}$', 'The card code is invalid'),
  266. missing=colander.drop)
  267. class AIMTransactionSchema(TransactionBaseSchema):
  268. customer_id = colander.SchemaNode(colander.String(),
  269. validator=colander.Length(max=60),
  270. missing=colander.drop)
  271. payment_id = colander.SchemaNode(colander.String(),
  272. validator=colander.Length(max=60),
  273. missing=colander.drop)
  274. address_id = colander.SchemaNode(colander.String(),
  275. validator=colander.Length(max=60),
  276. missing=colander.drop)
  277. email = colander.SchemaNode(colander.String(),
  278. validator=colander.Email(),
  279. missing=colander.drop)
  280. credit_card = CreditCardSchema(validator=CreditCardSchema.validator,
  281. missing=colander.drop)
  282. track_data = TrackDataSchema(validator=TrackDataSchema.validator,
  283. missing=colander.drop)
  284. retail = RetailSchema(validator=RetailSchema.validator,
  285. missing=colander.drop)
  286. bank_account = BankAccountSchema(validator=BankAccountSchema.validator,
  287. missing=colander.drop)
  288. billing = AddressSchema(missing=colander.drop)
  289. shipping = AddressSchema(missing=colander.drop)
  290. customer = CustomerSchema(missing=colander.drop)
  291. class CreditTransactionSchema(CIMBaseSchema):
  292. amount = colander.SchemaNode(colander.Decimal('0.01'),
  293. validator=colander.Range(0, 20000),
  294. required=True)
  295. class RefundTransactionSchema(colander.MappingSchema):
  296. amount = colander.SchemaNode(colander.Decimal('0.01'),
  297. validator=colander.Range(0, 20000),
  298. required=True)
  299. transaction_id = colander.SchemaNode(colander.String(),
  300. validator=colander.Length(max=60),
  301. required=True)
  302. last_four = colander.SchemaNode(colander.String(),
  303. validator=colander.Length(max=16),
  304. required=True)
  305. class ListBatchSchema(colander.MappingSchema):
  306. start = colander.SchemaNode(colander.Date(),
  307. missing=colander.drop)
  308. end = colander.SchemaNode(colander.Date(),
  309. missing=colander.drop)
  310. class UpdateRecurringSchema(colander.MappingSchema):
  311. name = colander.SchemaNode(colander.String(),
  312. validator=colander.Length(max=60),
  313. missing=colander.drop)
  314. start_date = colander.SchemaNode(colander.Date(),
  315. missing=colander.drop)
  316. trial_amount = colander.SchemaNode(colander.Decimal('0.01'),
  317. validator=colander.Range(0, 20000),
  318. missing=colander.drop)
  319. total_occurrences = colander.SchemaNode(colander.Integer(),
  320. validator=colander.Range(1, 9999),
  321. missing=colander.drop)
  322. trial_occurrences = colander.SchemaNode(colander.Integer(),
  323. validator=colander.Range(1, 99),
  324. missing=colander.drop)
  325. credit_card = CreditCardSchema(validator=CreditCardSchema.validator,
  326. missing=colander.drop)
  327. bank_account = BankAccountSchema(validator=BankAccountSchema.validator,
  328. missing=colander.drop)
  329. customer = CustomerBaseSchema(missing=colander.drop)
  330. order = OrderSchema(missing=colander.drop)
  331. billing = AddressSchema(missing=colander.drop)
  332. shipping = AddressSchema(missing=colander.drop)
  333. class CreateRecurringSchema(UpdateRecurringSchema):
  334. interval_length = colander.SchemaNode(colander.Integer(),
  335. validator=colander.Range(1, 999),
  336. required=True)
  337. interval_unit = colander.SchemaNode(colander.String(),
  338. validator=colander.OneOf(['days', 'months']),
  339. required=True)
  340. start_date = colander.SchemaNode(colander.Date(),
  341. missing=today)
  342. total_occurrences = colander.SchemaNode(colander.Integer(),
  343. validator=colander.Range(1, 9999),
  344. missing=9999)
  345. amount = colander.SchemaNode(colander.Decimal('0.01'),
  346. validator=colander.Range(0, 20000),
  347. required=True)
  348. class SortingSchema(colander.MappingSchema):
  349. order_by = colander.SchemaNode(colander.String(),
  350. validator=colander.OneOf(['id', 'name', 'status', 'createTimeStampUTC', 'lastName',
  351. 'firstName', 'accountNumber', 'amount', 'pastOccurrences']),
  352. missing='id')
  353. order_descending = colander.SchemaNode(colander.Boolean(),
  354. missing=False,
  355. required=False)
  356. class PagingSchema(colander.MappingSchema):
  357. limit = colander.SchemaNode(colander.Integer(),
  358. validator=colander.Range(1, 1000),
  359. missing=100)
  360. offset = colander.SchemaNode(colander.Integer(),
  361. validator=colander.Range(1, 100000),
  362. missing=1)
  363. class ListRecurringSchema(colander.MappingSchema):
  364. search_type = colander.SchemaNode(colander.String(),
  365. validator=colander.OneOf(['cardExpiringThisMonth', 'subscriptionActive',
  366. 'subscriptionInactive',
  367. 'subscriptionExpiringThisMonth']),
  368. required=True)
  369. sorting = SortingSchema(missing=colander.drop)
  370. paging = PagingSchema(missing=colander.drop)
  371. """Additional validation functions"""
  372. def require_payment_method(node, kw):
  373. """Ensures that a payment method is specified for the current node,"""
  374. if 'credit_card' not in kw and 'track_data' not in kw and 'bank_account' not in kw:
  375. raise colander.Invalid(node, 'You must provide either a credit card, some track data or a bank account')