4 * A charge is a charge (or credit) against an account and represents an actual
5 * transfer of funds. Each charge is normally associated with a cart, but a
6 * cart may have multiple charges. For example, a product may have a failed
7 * charge followed by a successful charge.
9 final class PhortuneCharge
extends PhortuneDAO
11 PhabricatorPolicyInterface
,
12 PhabricatorExtendedPolicyInterface
{
14 const STATUS_CHARGING
= 'charge:charging';
15 const STATUS_CHARGED
= 'charge:charged';
16 const STATUS_HOLD
= 'charge:hold';
17 const STATUS_FAILED
= 'charge:failed';
19 protected $accountPHID;
20 protected $authorPHID;
22 protected $providerPHID;
23 protected $merchantPHID;
24 protected $paymentMethodPHID;
25 protected $amountAsCurrency;
26 protected $amountRefundedAsCurrency;
27 protected $refundedChargePHID;
28 protected $refundingPHID;
30 protected $metadata = array();
32 private $account = self
::ATTACHABLE
;
33 private $cart = self
::ATTACHABLE
;
35 public static function initializeNewCharge() {
36 return id(new PhortuneCharge())
37 ->setStatus(self
::STATUS_CHARGING
)
38 ->setAmountRefundedAsCurrency(PhortuneCurrency
::newEmptyCurrency());
41 protected function getConfiguration() {
43 self
::CONFIG_AUX_PHID
=> true,
44 self
::CONFIG_SERIALIZATION
=> array(
45 'metadata' => self
::SERIALIZATION_JSON
,
47 self
::CONFIG_APPLICATION_SERIALIZERS
=> array(
48 'amountAsCurrency' => new PhortuneCurrencySerializer(),
49 'amountRefundedAsCurrency' => new PhortuneCurrencySerializer(),
51 self
::CONFIG_COLUMN_SCHEMA
=> array(
52 'paymentMethodPHID' => 'phid?',
53 'refundedChargePHID' => 'phid?',
54 'refundingPHID' => 'phid?',
55 'amountAsCurrency' => 'text64',
56 'amountRefundedAsCurrency' => 'text64',
59 self
::CONFIG_KEY_SCHEMA
=> array(
61 'columns' => array('cartPHID'),
63 'key_account' => array(
64 'columns' => array('accountPHID'),
66 'key_merchant' => array(
67 'columns' => array('merchantPHID'),
69 'key_provider' => array(
70 'columns' => array('providerPHID'),
73 ) + parent
::getConfiguration();
76 public static function getStatusNameMap() {
78 self
::STATUS_CHARGING
=> pht('Charging'),
79 self
::STATUS_CHARGED
=> pht('Charged'),
80 self
::STATUS_HOLD
=> pht('Hold'),
81 self
::STATUS_FAILED
=> pht('Failed'),
85 public static function getNameForStatus($status) {
86 return idx(self
::getStatusNameMap(), $status, pht('Unknown'));
89 public function isRefund() {
90 return $this->getAmountAsCurrency()->negate()->isPositive();
93 public function getStatusForDisplay() {
94 if ($this->getStatus() == self
::STATUS_CHARGED
) {
95 if ($this->getRefundedChargePHID()) {
99 $refunded = $this->getAmountRefundedAsCurrency();
101 if ($refunded->isPositive()) {
102 if ($refunded->isEqualTo($this->getAmountAsCurrency())) {
103 return pht('Fully Refunded');
105 return pht('%s Refunded', $refunded->formatForDisplay());
110 return self
::getNameForStatus($this->getStatus());
113 public function generatePHID() {
114 return PhabricatorPHID
::generateNewPHID(
115 PhortuneChargePHIDType
::TYPECONST
);
118 public function getMetadataValue($key, $default = null) {
119 return idx($this->metadata
, $key, $default);
122 public function setMetadataValue($key, $value) {
123 $this->metadata
[$key] = $value;
127 public function getAccount() {
128 return $this->assertAttached($this->account
);
131 public function attachAccount(PhortuneAccount
$account) {
132 $this->account
= $account;
136 public function getCart() {
137 return $this->assertAttached($this->cart
);
140 public function attachCart(PhortuneCart
$cart = null) {
145 public function getAmountRefundableAsCurrency() {
146 $amount = $this->getAmountAsCurrency();
147 $refunded = $this->getAmountRefundedAsCurrency();
149 // We can't refund negative amounts of money, since it does not make
150 // sense and is not possible in the various payment APIs.
152 $refundable = $amount->subtract($refunded);
153 if ($refundable->isPositive()) {
156 return PhortuneCurrency
::newEmptyCurrency();
161 /* -( PhabricatorPolicyInterface )----------------------------------------- */
164 public function getCapabilities() {
166 PhabricatorPolicyCapability
::CAN_VIEW
,
167 PhabricatorPolicyCapability
::CAN_EDIT
,
171 public function getPolicy($capability) {
172 return PhabricatorPolicies
::getMostOpenPolicy();
175 public function hasAutomaticCapability($capability, PhabricatorUser
$viewer) {
176 if ($capability === PhabricatorPolicyCapability
::CAN_VIEW
) {
177 $any_edit = PhortuneMerchantQuery
::canViewersEditMerchants(
178 array($viewer->getPHID()),
179 array($this->getMerchantPHID()));
189 /* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
192 public function getExtendedPolicy($capability, PhabricatorUser
$viewer) {
193 if ($this->hasAutomaticCapability($capability, $viewer)) {
200 PhabricatorPolicyCapability
::CAN_EDIT
,