File Coverage

blib/lib/Stancer/Role/Payment/Refund.pm
Criterion Covered Total %
statement 63 68 92.6
branch 9 10 90.0
condition n/a
subroutine 14 14 100.0
pod 2 2 100.0
total 88 94 93.6


line stmt bran cond sub pod time code
1             package Stancer::Role::Payment::Refund;
2              
3 14     14   237027 use 5.020;
  14         69  
4 14     14   95 use strict;
  14         48  
  14         415  
5 14     14   92 use warnings;
  14         32  
  14         1155  
6              
7             # ABSTRACT: Payment refund relative role
8             our $VERSION = '1.0.3'; # VERSION
9              
10 14     14   616 use Stancer::Core::Types qw(ArrayRef RefundInstance);
  14         33  
  14         1242  
11              
12 14     14   146 use Stancer::Exceptions::InvalidAmount;
  14         37  
  14         487  
13 14     14   663 use Stancer::Exceptions::MissingPaymentId;
  14         42  
  14         416  
14 14     14   2630 use Stancer::Refund::Status;
  14         37  
  14         557  
15 14     14   695 use Log::Any qw($log);
  14         12594  
  14         186  
16 14     14   10852 use Scalar::Util qw(blessed);
  14         58  
  14         1022  
17              
18 14     14   108 use Moo::Role;
  14         33  
  14         153  
19              
20             requires qw(_attribute_builder amount currency id);
21              
22 14     14   10080 use namespace::clean;
  14         48  
  14         104  
23              
24              
25             sub refundable_amount {
26 12     12 1 2410 my $this = shift;
27 12         354 my $amount = $this->amount;
28              
29 12         170 for (@{$this->refunds}) {
  12         304  
30 6         75 $amount -= $_->{amount};
31             }
32              
33 12         211 return $amount;
34             }
35              
36              
37             has refunds => (
38             is => 'rwp',
39             isa => ArrayRef[RefundInstance],
40 18     18   51594 builder => sub { $_[0]->_attribute_builder('refunds') },
41             coerce => sub {
42             my $data = shift;
43             my @refunds = ();
44              
45             if (defined $data) {
46             for my $refund (@{$data}) {
47             next if not defined $refund;
48              
49             if (blessed($refund) and blessed($refund) eq 'Stancer::Refund') {
50             push @refunds, $refund;
51             } else {
52             push @refunds, Stancer::Refund->new($refund);
53             }
54             }
55             }
56              
57             return \@refunds;
58             },
59             lazy => 1,
60             predicate => 1,
61             );
62              
63              
64             sub refund {
65 8     8 1 11977 my ($this, $amount) = @_;
66 8         324 my $refund = Stancer::Refund->new(payment => $this);
67 8         244 my $refunds = $this->refunds;
68              
69 8 100       178 Stancer::Exceptions::MissingPaymentId->throw() unless defined $this->id;
70              
71 7 100       45 if (defined $amount) {
72 6 100       39 if ($amount > $this->refundable_amount) {
73 2         61 my $refunded = $this->amount - $this->refundable_amount;
74 2         15 my $pattern = 'You are trying to refund (%.02f %s) more than paid (%.02f %s).';
75 2         86 my @params = (
76             $amount / 100,
77             uc $this->currency,
78             $this->amount / 100,
79             uc $this->currency,
80             );
81              
82 2 100       48 if ($refunded != 0) {
83 1         4 $pattern = 'You are trying to refund (%.02f %s) more than paid (%.02f %s with %.02f %s already refunded).';
84              
85 1         15 push @params, $refunded / 100;
86 1         34 push @params, uc $this->currency;
87             }
88              
89 2         48 my $message = sprintf $pattern, @params;
90              
91 2         59 Stancer::Exceptions::InvalidAmount->throw(message => $message);
92             }
93              
94 4         851 $refund->amount($amount);
95             }
96              
97 4         45 $refund->send();
98              
99 4         10 push @{$refunds}, $refund;
  4         21  
100 4         142 $this->_set_refunds($refunds);
101              
102 4         247 my $message = sprintf 'Refund of %.02f %s on payment "%s"', (
103             $refund->amount / 100,
104             uc $refund->currency,
105             $this->id,
106             );
107              
108 4         279 $log->info($message);
109              
110 4 50       375 if ($refund->status ne Stancer::Refund::Status::TO_REFUND) {
111 0         0 $this->_set_populated(0);
112 0         0 $this->populate();
113              
114 0         0 for my $item (@{ $this->refunds }) {
  0         0  
115 0         0 $item->payment($this);
116             }
117             }
118              
119 4         98 return $this;
120             }
121              
122             1;
123              
124             __END__
125              
126             =pod
127              
128             =encoding UTF-8
129              
130             =head1 NAME
131              
132             Stancer::Role::Payment::Refund - Payment refund relative role
133              
134             =head1 VERSION
135              
136             version 1.0.3
137              
138             =head1 ATTRIBUTES
139              
140             =head2 C<refundable_amount>
141              
142             Read-only integer.
143              
144             Paid amount available for a refund.
145              
146             =head2 C<refunds>
147              
148             Read-only array of C<Stancer::Refund> instance.
149              
150             List of refund made on the payment.
151              
152             =head1 METHODS
153              
154             =head2 C<< $payment->refund() : I<self> >>
155              
156             =head2 C<< $payment->refund(I<$amount>) : I<self> >>
157              
158             Refund a payment, or part of it.
159              
160             I<$amount>, if provided, must be at least 50. If not present, all paid amount we be refund.
161              
162             =head1 USAGE
163              
164             =head2 Logging
165              
166              
167              
168             We use the L<Log::Any> framework for logging events.
169             You may tell where it should log using any available L<Log::Any::Adapter> module.
170              
171             For example, to log everything to a file you just have to add a line to your script, like this:
172             #! /usr/bin/env perl
173             use Log::Any::Adapter (File => '/var/log/payment.log');
174             use Stancer::Role::Payment::Refund;
175              
176             You must import C<Log::Any::Adapter> before our libraries, to initialize the logger instance before use.
177              
178             You can choose your log level on import directly:
179             use Log::Any::Adapter (File => '/var/log/payment.log', log_level => 'info');
180              
181             Read the L<Log::Any> documentation to know what other options you have.
182              
183             =cut
184              
185             =head1 SECURITY
186              
187             =over
188              
189             =item *
190              
191             Never, never, NEVER register a card or a bank account number in your database.
192              
193             =item *
194              
195             Always uses HTTPS in card/SEPA in communication.
196              
197             =item *
198              
199             Our API will never give you a complete card/SEPA number, only the last four digits.
200             If you need to keep track, use these last four digit.
201              
202             =back
203              
204             =cut
205              
206             =head1 BUGS
207              
208             Please report any bugs or feature requests on the bugtracker website
209             L<https://gitlab.com/wearestancer/library/lib-perl/-/issues> or by email to
210             L<bug-stancer@rt.cpan.org|mailto:bug-stancer@rt.cpan.org>.
211              
212             When submitting a bug or request, please include a test-file or a
213             patch to an existing test-file that illustrates the bug or desired
214             feature.
215              
216             =head1 AUTHOR
217              
218             Joel Da Silva <jdasilva@cpan.org>
219              
220             =head1 COPYRIGHT AND LICENSE
221              
222             This software is Copyright (c) 2018-2024 by Stancer / Iliad78.
223              
224             This is free software, licensed under:
225              
226             The Artistic License 2.0 (GPL Compatible)
227              
228             =cut