|
7 | 7 | import iso8601
|
8 | 8 |
|
9 | 9 | from balanced.utils import cached_property, url_encode, classproperty
|
10 |
| -from balanced.exc import NoResultFound, MultipleResultsFound, ResourceError |
| 10 | +from balanced.exc import ( |
| 11 | + NoResultFound, MultipleResultsFound, ResourceError, BalancedError, |
| 12 | +) |
11 | 13 |
|
12 | 14 |
|
13 | 15 | LOGGER = logging.getLogger(__name__)
|
@@ -1163,6 +1165,147 @@ class Callback(Resource):
|
1163 | 1165 | resides_under_marketplace=True)
|
1164 | 1166 |
|
1165 | 1167 |
|
| 1168 | +class Customer(Resource): |
| 1169 | + """ |
| 1170 | + A customer represents a business or person within your Marketplace. A |
| 1171 | + customer can have many funding instruments such as cards and bank accounts |
| 1172 | + associated to them. |
| 1173 | + """ |
| 1174 | + __metaclass__ = resource_base(collection='customers', |
| 1175 | + resides_under_marketplace=False) |
| 1176 | + |
| 1177 | + def add_card(self, card): |
| 1178 | + """ |
| 1179 | + Associates the `Card` represented by `card` with this `Customer`. |
| 1180 | + """ |
| 1181 | + if isinstance(card, basestring): |
| 1182 | + self.card_uri = card |
| 1183 | + elif hasattr(card, 'uri'): |
| 1184 | + self.card_uri = card.uri |
| 1185 | + else: |
| 1186 | + self.card = card |
| 1187 | + self.save() |
| 1188 | + |
| 1189 | + def add_bank_account(self, bank_account): |
| 1190 | + """ |
| 1191 | + Associates the `BankAccount` represented by `bank_account` with this |
| 1192 | + `Customer`. |
| 1193 | + """ |
| 1194 | + if isinstance(bank_account, basestring): |
| 1195 | + self.bank_account_uri = bank_account |
| 1196 | + elif hasattr(bank_account, 'uri'): |
| 1197 | + self.bank_account_uri = bank_account.uri |
| 1198 | + else: |
| 1199 | + self.bank_account = bank_account |
| 1200 | + self.save() |
| 1201 | + |
| 1202 | + def debit(self, |
| 1203 | + amount=None, |
| 1204 | + appears_on_statement_as=None, |
| 1205 | + hold_uri=None, |
| 1206 | + meta=None, |
| 1207 | + description=None, |
| 1208 | + source_uri=None, |
| 1209 | + merchant_uri=None, |
| 1210 | + on_behalf_of=None, |
| 1211 | + **kwargs): |
| 1212 | + """ |
| 1213 | + :rtype: A `Debit` representing a flow of money from this Customer to |
| 1214 | + your Marketplace's escrow account. |
| 1215 | + :param amount: Amount to debit in cents, must be >= 50 |
| 1216 | + :param appears_on_statement_as: description of the payment as it needs |
| 1217 | + to appear on this customer's card statement |
| 1218 | + :param meta: Key/value collection |
| 1219 | + :param description: Human readable description |
| 1220 | + :param source_uri: A specific funding source such as a `Card` |
| 1221 | + associated with this customer. If not specified the `Card` most |
| 1222 | + recently added to this `Customer` is used. |
| 1223 | + :param on_behalf_of: the customer uri of whomever is providing the |
| 1224 | + service or delivering the product. |
| 1225 | + """ |
| 1226 | + if not any((amount, hold_uri)): |
| 1227 | + raise ResourceError('Must have an amount or hold uri') |
| 1228 | + if all([hold_uri, source_uri]): |
| 1229 | + raise ResourceError('Must specify only one of hold_uri OR source_uri') |
| 1230 | + |
| 1231 | + if on_behalf_of: |
| 1232 | + |
| 1233 | + if hasattr(on_behalf_of, 'uri'): |
| 1234 | + on_behalf_of = on_behalf_of.uri |
| 1235 | + |
| 1236 | + if not isinstance(on_behalf_of, basestring): |
| 1237 | + raise ValueError( |
| 1238 | + 'The on_behalf_of parameter should to be a customer uri' |
| 1239 | + ) |
| 1240 | + |
| 1241 | + if on_behalf_of == self.uri: |
| 1242 | + raise ValueError( |
| 1243 | + 'The on_behalf_of parameter MAY NOT be the same customer' |
| 1244 | + ' as the account you are debiting!' |
| 1245 | + ) |
| 1246 | + |
| 1247 | + meta = meta or {} |
| 1248 | + return Debit( |
| 1249 | + uri=self.debits_uri, |
| 1250 | + amount=amount, |
| 1251 | + appears_on_statement_as=appears_on_statement_as, |
| 1252 | + hold_uri=hold_uri, |
| 1253 | + meta=meta, |
| 1254 | + description=description, |
| 1255 | + source_uri=source_uri, |
| 1256 | + merchant_uri=merchant_uri, |
| 1257 | + on_behalf_of_uri=on_behalf_of, |
| 1258 | + **kwargs |
| 1259 | + ).save() |
| 1260 | + |
| 1261 | + def credit(self, |
| 1262 | + amount, |
| 1263 | + description=None, |
| 1264 | + meta=None, |
| 1265 | + destination_uri=None, |
| 1266 | + appears_on_statement_as=None, |
| 1267 | + debit_uri=None, |
| 1268 | + **kwargs): |
| 1269 | + """ |
| 1270 | + Returns a new Credit representing a transfer of funds from your |
| 1271 | + Marketplace's escrow account to this Customer. |
| 1272 | +
|
| 1273 | + :param amount: Amount to hold in cents |
| 1274 | + :param description: Human readable description |
| 1275 | + :param meta: Key/value collection |
| 1276 | + :param destination_uri: A specific funding destination such as a |
| 1277 | + `BankAccount` associated with this customer. |
| 1278 | + :param appears_on_statement_as: description of the payment as it needs |
| 1279 | + :param debit_uri: the debit corresponding to this particular credit |
| 1280 | +
|
| 1281 | + Returns: |
| 1282 | + A `Credit` representing the transfer of funds from your |
| 1283 | + Marketplace's escrow account to this Customer. |
| 1284 | + """ |
| 1285 | + meta = meta or {} |
| 1286 | + return Credit( |
| 1287 | + uri=self.credits_uri, |
| 1288 | + amount=amount, |
| 1289 | + description=description, |
| 1290 | + meta=meta, |
| 1291 | + destination_uri=destination_uri, |
| 1292 | + appears_on_statement_as=appears_on_statement_as, |
| 1293 | + debit_uri=debit_uri, |
| 1294 | + **kwargs |
| 1295 | + ).save() |
| 1296 | + |
| 1297 | + @property |
| 1298 | + def active_card(self): |
| 1299 | + cards = self.cards.filter(is_valid=True, sort='created_at,desc') |
| 1300 | + return cards[0] if cards else None |
| 1301 | + |
| 1302 | + @property |
| 1303 | + def active_bank_account(self): |
| 1304 | + bank_accounts = self.bank_accounts.filter(is_valid=True, |
| 1305 | + sort='created_at,desc') |
| 1306 | + return bank_accounts[0] if bank_accounts else None |
| 1307 | + |
| 1308 | + |
1166 | 1309 | class FilterExpression(object):
|
1167 | 1310 | def __init__(self, field, op, value, inv_op):
|
1168 | 1311 | self.field = field
|
|
0 commit comments