Annotation of RT/Invoicing/lib/RTI/State.pm, Revision 1.2
1.1 andrew 1: package RTI::State;
2: use strict;
3: use warnings;
4:
5: use Carp;
6:
7: use DateTime;
8:
9: use 5.010;
10:
11: use YAML::Any qw/ LoadFile DumpFile /;
12:
13: my $file = '';
14:
15: sub new {
16: my $class;
17: ( $class, $file ) = @_;
18:
19: my $self = { lastinvoice => 0, };
20: if ( -e $file ) {
21: $self = LoadFile($file) or die "Unable to load state: $!";
22:
23: $self->{lastinvoice} ||= 0;
24: while ( my ( $id, $invoice ) = each %{ $self->{invoice} } ) {
25: $self->{lastinvoice} = $id if $self->{lastinvoice} < $id;
26: $invoice->{id} = $id;
27: }
28: }
29:
30: bless $self, $class;
31:
32: die "Need to pass filename to new: $!" unless $file;
33:
34: return $self;
35: }
36:
37: sub next_invoice_id {
38: my ($self) = @_;
39: return $self->{lastinvoice} + 1;
40: }
41:
42: sub add_invoice {
43: my ( $self, $invoice ) = @_;
44:
45: my $id = $invoice->{id} || $self->next_invoice_id;
46:
47: croak "Can't add duplicate invoice $id\n"
48: if exists $self->{invoice}->{$id};
49:
50: $invoice->{id} ||= $id;
51: $invoice->{invdate} ||= DateTime->now( time_zone => 'local' )->ymd,
52:
53: $self->{lastinvoice} = $id if $self->{lastinvoice} < $id;
54:
55: my %li;
56: foreach my $k (
57: qw/
58: id custid
59: file transactions
60: invdate start end
61: total past_due total_due
62: /
63: )
64: {
65: my $v = $invoice->{$k};
66:
67: if ( defined $v && length $v ) {
68: if ( ref $v eq 'DateTime' ) {
69: $li{$k} = $v->ymd;
70: }
71: else {
72: $li{$k} = $v;
73: }
74: }
75: }
76:
77: $self->{invoice}->{ $self->{lastinvoice} } = \%li;
78: delete $self->{_tables};
79:
80: return $self->{lastinvoice};
81: }
82:
83: sub get_invoice{
84: my ( $self, $id ) = @_;
85: return $self->{invoice}->{$id};
86: }
87:
88: sub last_invoice {
89: my ( $self, $custid ) = @_;
90:
91: if ( !$self->{_table}->{last_invoice} ) {
92: my $invoices = $self->{invoice};
93: foreach my $id ( sort { $a <=> $b } keys %{$invoices} ) {
94: my $inv = $invoices->{$id};
95: next unless $inv->{custid};
96: $self->{_table}->{last_invoice}->{ $inv->{custid} } = $inv;
97: }
98: }
99:
100: return $self->{_table}->{last_invoice}->{$custid};
101: }
102:
103: sub txn_is_invoiced {
104: my ( $self, $txn ) = @_;
105:
106: if ( !$self->{_table}->{txn} ) {
107: my $invoices = $self->{invoice};
108: foreach my $id ( sort { $a <=> $b } keys %{$invoices} ) {
109: my $inv = $invoices->{$id};
110: foreach my $t ( @{ $inv->{transactions} } ) {
111: $self->{_table}->{txn}->{$t} = 1;
112: }
113: }
114: }
115: return $self->{_table}->{txn}->{$txn};
116: }
117:
118: sub unpaid_invoices {
119: my ($self, $custid) = @_;
120:
121: $self->_match_payments;
1.2 ! andrew 122: return defined $custid
! 123: ? $self->{_table}->{unpaid}->{$custid}
! 124: : $self->{_table}->{unpaid};
1.1 andrew 125: }
126:
127: sub save {
128: my ($self) = @_;
129:
130: delete $self->{_table};
131: delete $self->{lastinvoice};
132: foreach my $invoice ( values %{ $self->{invoice} } ) {
133: delete $invoice->{id};
134: }
135: DumpFile( $file, {%$self} ) or die "Unable to save state: $!";
136: }
137:
138: sub _match_payments {
139: my ($self) = @_;
140:
141: return if $self->{_table}{credit} && $self->{_table}{unpaid};
142:
143: my $invoices = $self->{invoice};
144: my %owes = map { $_ => $invoices->{$_}->{total} } keys %{ $invoices };
145:
146: my %credit;
147:
148: foreach my $custid ( keys %{ $self->{payment} } ) {
149: $credit{$custid} = 0;
150:
151: my $payments = $self->{payment}->{$custid};
152: foreach my $p ( @{$payments} ) {
153: my $paid = $p->{paid};
154: $p->{invoices} ||= [];
155:
156: foreach my $id ( @{ $p->{invoices} } ) {
157: $owes{$id} ||= 0;
158:
159: if ( $owes{$id} == $paid ) {
160: $owes{$id} = 0;
161: $paid = 0;
162: }
163: elsif ( $owes{$id} > $paid ) {
164: $owes{$id} -= $paid;
165: $paid = 0;
166: }
167: elsif ( $owes{$id} < $paid ) {
168: $paid -= $owes{$id};
169: $owes{$id} = 0;
170: }
171: }
172:
173: $credit{$custid} += $paid;
174: }
175:
176: delete $credit{$custid} unless $credit{$custid};
177: }
178:
179: foreach my $id ( sort { $b <=> $a } keys %owes ) {
180: my $i = $invoices->{$id};
181: my $custid = $i->{custid} or next;
182:
183: my $owes = sprintf "%0.2f", $owes{$id} || 0;
184: my $paid = sprintf "%0.2f", $credit{$custid} || 0;
185:
186: if ( $owes == $paid ) {
187: $owes = 0;
188: $paid = 0;
189: }
190: elsif ( $owes > $paid ) {
191: $owes -= $paid;
192: $paid = 0;
193: }
194: elsif ( $owes < $paid ) {
195: $paid -= $owes;
196: $owes = 0;
197: }
198:
199: $self->{_table}{unpaid}{$custid}{$id} = $owes if $owes;
200:
201: if ($paid) {
202: $credit{$custid} = $paid;
203: }
204: elsif (exists $credit{$custid}) {
205: delete $credit{$custid};
206: }
207: }
208:
209: $self->{_table}{credit} = \%credit;
210: }
211:
212: 1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>