RT# 83450 - fixed rateplan export
[freeside.git] / FS / FS / part_export / batch_Common.pm
1 package FS::part_export::batch_Common;
2
3 use strict;
4 use base 'FS::part_export';
5 use FS::Record qw(qsearch qsearchs);
6 use FS::export_batch;
7 use FS::export_batch_item;
8 use Storable qw(nfreeze thaw);
9 use MIME::Base64 qw(encode_base64 decode_base64);
10
11 =head1 DESCRIPTION
12
13 FS::part_export::batch_Common should be inherited by any export that stores
14 pending service changes and processes them all at once.  It provides the 
15 external interface, and has an internal interface that the subclass must 
16 implement.
17
18 =head1 INTERFACE
19
20 ACTION in all of these methods is one of 'insert', 'delete', 'replace',
21 'suspend', 'unsuspend', 'pkg_change', or 'relocate'.
22
23 ARGUMENTS is the arguments to the export_* method:
24
25 - for insert, the new service
26
27 - for suspend, unsuspend, or delete, the service to act on
28
29 - for replace, the new service, followed by the old service
30
31 - for pkg_change, the service, followed by the new and old packages 
32   (as L<FS::cust_pkg> objects)
33
34 - for relocate, the service, followed by the new location and old location
35   (as L<FS::cust_location> objects)
36
37 =over 4
38
39 =item immediate ACTION, ARGUMENTS
40
41 This is called immediately from the export_* method, and does anything
42 that needs to happen right then, except for inserting the 
43 L<FS::export_batch_item> record.  Optional.  If it exists, it can return
44 a non-empty error string to cause the export to fail.
45
46 =item data ACTION, ARGUMENTS
47
48 This is called just before inserting the batch item, and returns a scalar
49 to store in the item's C<data> field.  If the export needs to remember 
50 anything about the service for the later batch-processing stage, it goes 
51 here.  Remember that if the service is being deleted, the export will need
52 to remember enough information to unprovision it when it's no longer in the 
53 database.
54
55 If this returns a reference, it will be frozen down with Base64-Storable.
56
57 =item process BATCH
58
59 This is called from freeside-daily, once for each batch still in the 'open'
60 or 'closed' state.  It's expected to do whatever needs to be done with the 
61 batch, and report failure via die().
62
63 =back
64
65 =head1 METHODS
66
67 =over 4
68
69 =cut
70
71 sub export_insert {
72   my $self = shift;
73   my $svc = shift;
74
75   $self->immediate('insert', $svc) || $self->create_item('insert', $svc);
76 }
77
78 sub export_delete {
79   my $self = shift;
80   my $svc = shift;
81
82   $self->immediate('delete', $svc) || $self->create_item('delete', $svc);
83 }
84
85 sub export_suspend {
86   my $self = shift;
87   my $svc = shift;
88
89   $self->immediate('suspend', $svc) || $self->create_item('suspend', $svc);
90 }
91
92 sub export_unsuspend {
93   my $self = shift;
94   my $svc = shift;
95
96   $self->immediate('unsuspend', $svc) || $self->create_item('unsuspend', $svc);
97 }
98
99 sub export_replace {
100   my $self = shift;
101   my $new = shift;
102   my $old = shift;
103
104   $self->immediate('replace', $new, $old) 
105   || $self->create_item('replace', $new, $old)
106 }
107
108 sub export_relocate {
109   my $self = shift;
110   my $svc = shift;
111   my $new_loc = shift;
112   my $old_loc = shift;
113
114   $self->immediate('relocate', $svc, $new_loc, $old_loc)
115   || $self->create_item('relocate', $svc, $new_loc, $old_loc)
116 }
117
118 sub export_pkg_change {
119   my $self = shift;
120   my $svc = shift;
121   my $new_pkg = shift;
122   my $old_pkg = shift;
123
124   $self->immediate('pkg_change', $svc, $new_pkg)
125   || $self->create_item('pkg_change', $svc, $new_pkg)
126 }
127
128 =item create_item ACTION, ARGUMENTS
129
130 Creates and inserts the L<FS::export_batch_item> record for the action.
131
132 =cut
133
134 sub create_item {
135   my $self = shift;
136   my $action = shift;
137   my $svc = shift;
138
139   # get memo field
140   my $data = $self->data($action, $svc, @_);
141   my $frozen = '';
142   if (ref $data) {
143     $data = base64_encode(nfreeze($data));
144     $frozen = 'Y';
145   }
146   my $batch_item = FS::export_batch_item->new({
147       'svcnum'    => $svc->svcnum,
148       'action'    => $action,
149       'data'      => $data,
150       'frozen'    => $frozen,
151   });
152   return $self->add_to_batch($batch_item);
153 }
154
155 sub immediate { # stub
156   '';
157 }
158
159 =item add_to_batch ITEM
160
161 Actually inserts ITEM into the appropriate open batch.  All fields in ITEM
162 will be populated except for 'batchnum'.  By default, all items for a 
163 single export will go into the same batch, but subclass exports may override
164 this method.
165
166 =cut
167
168 sub add_to_batch {
169   my $self = shift;
170   my $batch_item = shift;
171   $batch_item->set( 'batchnum', $self->open_batch->batchnum );
172
173   $batch_item->insert;
174 }
175
176 =item open_batch
177
178 Returns the current open batch for this export.  If there isn't one yet,
179 this will create one.
180
181 =cut
182
183 sub open_batch {
184   my $self = shift;
185   my $batch = qsearchs('export_batch', { status => 'open',
186                                          exportnum => $self->exportnum });
187   if (!$batch) {
188     $batch = FS::export_batch->new({
189         status    => 'open',
190         exportnum => $self->exportnum
191     });
192     my $error = $batch->insert;
193     die $error if $error;
194   }
195   $batch;
196 }
197
198 =back
199
200 =cut
201
202 1;