├── README.md
├── autoagreement.pm
├── autodata.pm
├── autoform.pm
├── autoinfopage.pm
├── automobile_api.pm
├── autopayment.pm
├── autosms.pm
├── css
├── autoform.css
├── tip-redsimple.css
└── tip-yellowsimple.css
├── images
├── 1x1.png
├── app-helper.png
├── autoform_wait.gif
├── biometric_pass.png
├── pbar-gray-gray.png
├── pbar-gray-white.png
├── pbar-red-gray.png
├── pbar-red-red.png
├── pbar-red-white.png
├── pbar-white-gray.png
├── pbar-white-red.png
├── tip-redsimple_arrows.gif
├── tip-yellowsimple_arrows.gif
├── type_jpg.png
├── type_pdf.png
├── type_png.png
├── type_tiff.png
└── type_unk.png
├── model
├── autodata_type_c.pm
├── autodata_type_c_spb.pm
├── autodata_type_checkdoc.pm
├── autodata_type_d.pm
└── autodata_type_rinnuovo.pm
├── scripts
├── autoform_clean.pl
├── autoform_fox.pl
├── autoform_softban.pl
└── autoform_softban_warn.pl
└── templates
├── autoform.tt2
├── autoform_address_check.tt2
├── autoform_confirm.tt2
├── autoform_docstatus.tt2
├── autoform_edit.tt2
├── autoform_finish.tt2
├── autoform_info.tt2
├── autoform_info_entry.tt2
├── autoform_list.tt2
├── autoform_pcode.tt2
├── autoform_upload.tt2
└── js_elements.tt2
/README.md:
--------------------------------------------------------------------------------
1 | # autoform
2 | Flexible and stable appointment system
3 |
--------------------------------------------------------------------------------
/autoagreement.pm:
--------------------------------------------------------------------------------
1 | package VCS::Site::autoagreement;
2 | use strict;
3 | use utf8;
4 |
5 | use Math::Random::Secure qw(irand);
6 | use Data::Dumper;
7 |
8 | sub new
9 | # //////////////////////////////////////////////////
10 | {
11 | my ( $class, $pclass, $vars ) = @_;
12 |
13 | my $self = bless {}, $pclass;
14 |
15 | $self->{ 'VCS::Vars' } = $vars;
16 |
17 | return $self;
18 | }
19 |
20 | sub create_online_appointment
21 | # //////////////////////////////////////////////////
22 | {
23 | my $self = shift;
24 |
25 | my $app_id = $self->{ af }->query( 'sel1', __LINE__, "
26 | SELECT CreatedApp FROM AutoToken WHERE Token = ?", $self->{ token }
27 | );
28 |
29 | $self->{ af }->log(
30 | "autoinfo_remote", "удалённая запись после проверки документов", $app_id
31 | );
32 |
33 | $self->{ af }->query( 'query', __LINE__, "
34 | UPDATE Appointments SET Status = 13, AppDate = now(), CenterID = 47 WHERE ID = ?", {}, $app_id
35 | );
36 |
37 | $self->{ af }->query( 'query', __LINE__, "
38 | UPDATE AutoToken SET ServiceType = 3 WHERE Token = ?", {}, $self->{ token }
39 | );
40 | }
41 |
42 | sub create_sms_agreements_if_need
43 | # //////////////////////////////////////////////////
44 | {
45 | my $self = shift;
46 |
47 | my ( $token_id, $already ) = $self->{ af }->query( 'sel1', __LINE__, "
48 | SELECT AutoToken.ID, DocUploadedAgreements.ID FROM AutoToken
49 | LEFT JOIN DocUploadedAgreements ON AutoToken.ID = DocUploadedAgreements.Token
50 | WHERE AutoToken.Token = ?", $self->{ token }
51 | );
52 |
53 | return if $already;
54 |
55 | my $now = $self->{ vars }->get_system->now_date();
56 |
57 | $self->{ af }->query( 'query', __LINE__, "
58 | LOCK TABLES DocUploadedAgreements WRITE, Templates READ, PriceRate READ, PriceList READ"
59 | );
60 |
61 | my $maxAgr = $self->{ af }->query( 'sel1', __LINE__, "
62 | SELECT MAX(Agreement) FROM DocUploadedAgreements WHERE AgrDate = ?", $now
63 | );
64 |
65 | $maxAgr =~ /(\d{2})(\d{6})(\d{6})/;
66 |
67 | my $maxOrder = sprintf('%06d', ( $2 ? $2 + 1 : 1 ) );
68 |
69 | $now =~ /(\d{2})(\d{2})\-(\d{2})\-(\d{2})/;
70 |
71 | my $agreementNo = "46$maxOrder$3$4$2";
72 |
73 | my $template = $self->{ af }->query( 'sel1', __LINE__, "
74 | SELECT ID FROM Templates WHERE TDate <= curdate() AND isJur=0 AND CenterID=46 ORDER BY TDate DESC LIMIT 1"
75 | );
76 |
77 | my $rate = $self->{ vars }->admfunc->getRate( $self->{ vars }, 'RUR', $now, 46 );
78 |
79 | $self->{ af }->query( 'query', __LINE__, "
80 | INSERT INTO DocUploadedAgreements (Token, Agreement, RateID, Template, AgrDate) VALUES (?, ?, ?, ?, ?)", {},
81 | $token_id, $agreementNo, $rate, $template, $now
82 | );
83 |
84 | $self->{ af }->query( 'query', __LINE__, "UNLOCK TABLES" );
85 | }
86 |
87 | sub get_sms_agreements
88 | # //////////////////////////////////////////////////
89 | {
90 | my $self = shift;
91 |
92 | my $agreement = $self->{ af }->query( 'sel1', __LINE__, "
93 | SELECT Agreement FROM AutoToken
94 | JOIN DocUploadedAgreements ON AutoToken.ID = DocUploadedAgreements.Token
95 | WHERE AutoToken.Token = ?", $self->{ token }
96 | );
97 |
98 | $agreement =~ s/^([0-9]{2})([0-9]{6})([0-9]{6})$/$1.$2.$3/;
99 |
100 | return $agreement;
101 | }
102 |
103 | sub create_online_agreement
104 | # //////////////////////////////////////////////////
105 | {
106 | my $self = shift;
107 |
108 | $self->{ af }->query( 'query', __LINE__, "
109 | LOCK TABLES
110 | DocHistory WRITE, DocPack WRITE, DocPackInfo WRITE, DocPackList WRITE,
111 | DocPackOptional WRITE, UserLog WRITE, Templates WRITE,
112 | Appointments WRITE, AppData WRITE, DocRequest WRITE, DocComments WRITE, AutoRemote WRITE,
113 | AutoPayment READ, AutoToken READ, VisaTypes READ, PriceRate READ, PriceList READ"
114 | );
115 |
116 | my $now = $self->{ vars }->get_system->now_date();
117 |
118 | my $agreementNo = $self->{ vars }->admfunc->getAgrNumber( $self->{ vars }, 47, $now );
119 |
120 | my $rate = $self->{ vars }->admfunc->getRate( $self->{ vars }, 'RUR', $now, 47 );
121 |
122 | my ( $sms_price, undef ) = $self->{ af }->get_payment_price( "sms" );
123 |
124 | my ( $service_fee, $count ) = $self->{ af }->get_payment_price( "service" );
125 |
126 | my $app = $self->{ af }->query( 'selallkeys', __LINE__, "
127 | SELECT Appointments.ID as AppID, FoxAddress, FName, LName, MName,
128 | Appointments.VType, Appointments.ID, SMS, Phone, Mobile, PassNum, PassDate,
129 | PassWhom, Appointments.Address, AutoRemote.BankID, AutoRemote.PVC,
130 | AutoToken.EMail, AutoRemote.ID as AutoRemoteID
131 | FROM AutoToken
132 | JOIN Appointments ON AutoToken.CreatedApp = Appointments.ID
133 | JOIN AutoRemote ON Appointments.ID = AutoRemote.AppID
134 | WHERE Token = ?", $self->{ token }
135 | )->[0];
136 |
137 | my $sms = $self->{ af }->query( 'sel1', __LINE__, "
138 | SELECT AutoPayment.ID FROM AutoPayment
139 | JOIN AutoToken ON AutoPayment.AutoID = AutoToken.CreatedApp
140 | WHERE Token = ? AND AutoPayment.`Type` = 'sms' AND PaymentStatus = 2",
141 | $self->{ token }
142 | );
143 |
144 | $sms = ( $sms ? 1 : 0 );
145 |
146 | my $dsum = ( $service_fee * $count ) + ( $sms ? $sms_price : 0 );
147 |
148 | my $template = $self->{ af }->query( 'sel1', __LINE__, "
149 | SELECT ID FROM Templates WHERE TDate <= curdate() AND isJur=0 AND CenterID=47 ORDER BY TDate DESC LIMIT 1"
150 | );
151 |
152 | $self->{ af }->query( 'query', __LINE__, "
153 | INSERT INTO DocPack (
154 | LastUpdate, Cur, RateID, Address, FName, LName, MName, DSum, ADate, PDate, PStatus, Login,
155 | AgreementNo, PType, Urgent, VisaType, AppID, Shipping, SMS, Phone, DovDate, DovNum, Template,
156 | CenterID, Mobile, PassNum, PassDate, PassWhom, ShippingAddress, XeroxPage, AnketaSrv, PrintSrv,
157 | PhotoSrv, VIPSrv, InsSum, ServSum, ShipNum, SkipIns, Translate, PersonalNo, TShipSum, isNewDHL,
158 | ConcilPaymentDate, officeToReceive, ShippingPhone, InsData, NoReceived
159 | ) VALUES (
160 | curdate(), 'RUR', ?, ?, ?, ?, ?, ?, now(), now(), 25, ?, ?, 2, 0, ?, ?, 0, ?, ?, ?, ?, ?, 47,
161 | ?, ?, ?, ?, ?, 0, 0, 0, 0, 0, 0, ?, ?, 0, 0, '', 0, 0, now(), ?, ?, 0, 0
162 | )", {},
163 | $rate, $app->{ Address }, $app->{ FName }, $app->{ LName }, $app->{ MName }, $dsum, 'remote_script',
164 | $agreementNo, $app->{ VType }, $app->{ ID }, $sms, $app->{ Phone }, '0000-00-00', 0, $template,
165 | $app->{ Phone }, $app->{ PassNum }, $app->{ PassDate }, $app->{ PassWhom }, 'адрес ещё не указан',
166 | $service_fee, 0, 0, 0, $app->{ Mobile },
167 | );
168 |
169 | my $doc_id = $self->{ af }->query( 'sel1', __LINE__, "SELECT last_insert_id()") || 0;
170 |
171 | my @alph = split( //, '0123456789abcdefghigklmnopqrstuvwxyz' );
172 | my $feedback_token = "";
173 | $feedback_token .= $alph[ int( irand( 36 ) ) ] for ( 1..24 );
174 |
175 | $self->{ af }->query( 'query', __LINE__, "
176 | INSERT INTO DocPackOptional (DocPackID, ShippingFree, Reject, FeedbackKey, SendInfoEmail) VALUES (?, 0, 0, ?, ?)", {},
177 | $doc_id, $feedback_token, $app->{ EMail }
178 | );
179 |
180 | $self->{ af }->query( 'query', __LINE__, "
181 | INSERT INTO DocComments (DocID, Login, CommentText, CommentDate) VALUES (?, ?, ?, now())", {},
182 | $doc_id, 'remote_script', 'Договор сформирован автоматически системой удалённой подачи; договор был оплачен картой через платёжный шлюз'
183 | );
184 |
185 | my $bankids = parse_complex_data( $self, $app->{ BankID } );
186 |
187 | my $appdata = $self->{ af }->query( 'selallkeys', __LINE__, "
188 | SELECT ID, RFName, RMName, RLName, PassNum, BirthDate, AppSDate
189 | FROM AppData WHERE AppID = ? AND Status != 2", $app->{ AppID }
190 | );
191 |
192 | my $docpackinfo = {};
193 |
194 | for ( @$appdata ) {
195 |
196 | my $id = $bankids->{ $_->{ ID } } || " ";
197 |
198 | $docpackinfo->{ $id } = [] unless ref( $docpackinfo->{ $id } ) eq 'ARRAY';
199 |
200 | push( @{ $docpackinfo->{ $id } }, $_ );
201 | }
202 |
203 | for my $info_bankid ( keys %$docpackinfo ) {
204 |
205 | $self->{ af }->query( 'query', __LINE__, "
206 | INSERT INTO DocPackInfo (PackID, BankID, VisaCnt) VALUES (?, ?, ?)", {},
207 | $doc_id, $info_bankid, scalar( @{ $docpackinfo->{ $info_bankid } } )
208 | );
209 |
210 | my $info_id = $self->{ af }->query( 'sel1', __LINE__, "SELECT last_insert_id()") || 0;
211 |
212 | for ( @{ $docpackinfo->{ $info_bankid } } ) {
213 |
214 | $self->{ af }->query( 'query', __LINE__, "
215 | INSERT INTO DocPackList (
216 | PackInfoID, CBankID, FName, LName, MName, isChild, PassNum, SDate, Login,
217 | Status, ApplID, iNRes, Concil, MobileNums, ShipAddress, ShipNum, RTShipSum,
218 | FlyDate, ShipPhone, ShipMail, BthDate, AgeCatA
219 | ) VALUES (
220 | ?, ?, ?, ?, ?, ?, ?, ?, now(), 25, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
221 | )", {},
222 | $info_id, $info_bankid, $_->{ RFName }, $_->{ RLName }, $_->{ RMName }, 0,
223 | $_->{ PassNum }, 'remote_script', $_->{ ID }, 0, 0, ' ', ' ', 0, 0,
224 | $_->{ AppSDate }, 0, 0, $_->{ BirthDate }, 0
225 | );
226 |
227 | my $list_id = $self->{ af }->query( 'sel1', __LINE__, "SELECT last_insert_id()") || 0;
228 |
229 | $self->{ af }->query( 'query', __LINE__, "
230 | INSERT INTO DocRequest (PackListID, VisaDataNumberEntries, VisaDataPurposeTravel,
231 | VisaDataDuration, VisaDataMainDestination)
232 | VALUES (?, 'M', 'TU', '90', 'I')", {},
233 | $list_id,
234 | );
235 |
236 | my $secons_shift = 0;
237 |
238 | for my $sec ( 1, 2, 25 ) {
239 |
240 | $self->{ af }->query( 'query', __LINE__, "
241 | INSERT INTO DocHistory (DocID, PassNum, Login, HDate, StatusID, BankID)
242 | VALUES (?, ?, ?, DATE_ADD(now(), INTERVAL ? SECOND), ?, ?)", {},
243 | $doc_id, $_->{ PassNum }, 'remote_script', $secons_shift, $sec, $info_bankid
244 | );
245 |
246 | $secons_shift += 1;
247 | };
248 | }
249 | }
250 |
251 |
252 | $self->{ af }->query( 'query', __LINE__, "
253 | UPDATE AutoRemote SET Agreement = ? WHERE ID = ?", {},
254 | $doc_id, $app->{ AutoRemoteID }
255 | );
256 |
257 | $self->{ af }->query( 'query', __LINE__, "UNLOCK TABLES" );
258 |
259 | $agreementNo =~ s/^([0-9]{2})([0-9]{6})([0-9]{6})$/$1.$2.$3/;
260 |
261 | return $agreementNo;
262 | }
263 |
264 | sub parse_complex_data
265 | # //////////////////////////////////////////////////
266 | {
267 | my ( $self, $data ) = @_;
268 |
269 | my @data_arr = split( /\|/, $data );
270 |
271 | my $data = {};
272 |
273 | for ( @data_arr ) {
274 |
275 | my @data_pair = split( /:/, $_ );
276 |
277 | $data->{ $data_pair[0] } = $data_pair[1];
278 | }
279 |
280 | return $data;
281 | }
282 |
283 | 1;
--------------------------------------------------------------------------------
/automobile_api.pm:
--------------------------------------------------------------------------------
1 | package VCS::Site::automobile_api;
2 | use strict;
3 |
4 | use VCS::Vars;
5 | use VCS::Site::autodata;
6 |
7 | use Data::Dumper;
8 | use JSON;
9 |
10 | sub get_mobile_api
11 | # //////////////////////////////////////////////////
12 | {
13 | my ( $self, $token ) = @_;
14 |
15 | my $vars = $self->{ 'VCS::Vars' };
16 |
17 | my $table_id = $self->get_current_table_id();
18 |
19 | my $api = $vars->getparam( 'mobile_api' ) || '';
20 |
21 | return get_api_head( $self, 1 ) if $self->{ token } =~ /^\d\d$/;
22 |
23 | return get_values_for_api( $self ) if $api =~ /^get_appdata$/i;
24 |
25 | return set_values_from_api( $self ) if $api =~ /^set_appdata$/i;
26 |
27 | return get_api_centers( $self ) if $api =~ /^get_centers$/i;
28 |
29 | return get_doc_status( $self ) if $api =~ /^get_doc_status$/i;
30 |
31 | return get_advertisment() if $api =~ /^get_advertisment$/i;
32 |
33 | return get_push( $self, $1 ) if $api =~ /^push_(on|off)$/i;
34 |
35 | return get_api_head( $self, 2 ) if $api !~ /^get_token$/i;
36 |
37 | return get_api_head( $self, 0 );
38 | }
39 |
40 | sub get_values_for_api
41 | # //////////////////////////////////////////////////
42 | {
43 | my $self = shift;
44 |
45 | my $delete_fields = VCS::Site::autodata::get_mobile_api_fields( 'to_delete' );
46 |
47 | my $tables_id = $self->get_current_table_id();
48 |
49 | my $result = get_api_head( $self, 0 );
50 |
51 | $result->{ data }->{ appointments } = $self->query( 'selallkeys', __LINE__, "
52 | SELECT * FROM AutoAppointments WHERE ID = ?", $tables_id->{ AutoAppointments }
53 | )->[0];
54 |
55 | $result->{ data }->{ date } = $result->{ data }->{ appointments }->{ AppDate };
56 |
57 |
58 | my ( $start, $end ) = $self->query( 'sel1', __LINE__, "
59 | SELECT TStart, TEnd FROM TimeData WHERE SlotID = ?", $result->{ data }->{ appointments }->{ TimeslotID }
60 | );
61 |
62 | $_ = $self->{ vars }->get_system->time_to_str( $_ ) for ( $start, $end );
63 |
64 | $result->{ data }->{ time } = "$start - $end";
65 |
66 | $result->{ data }->{ center } = $self->query( 'sel1', __LINE__, "
67 | SELECT BName FROM Branches WHERE ID = ?",
68 | $result->{ data }->{ appointments }->{ CenterID }
69 | );
70 |
71 | my ( $status, $appid ) = $self->query( 'sel1', __LINE__, "
72 | SELECT Finished, CreatedApp FROM AutoToken WHERE ID = ?", $tables_id->{ AutoToken }
73 | );
74 |
75 | $result->{ data }->{ status } = ( $status ? 'finished' : 'ongoing' );
76 |
77 | if ( $status) {
78 |
79 | my $appnum = $self->query( 'sel1', __LINE__, "
80 | SELECT AppNum FROM Appointments WHERE ID = ?", $appid
81 | );
82 |
83 | $appnum =~ s!(\d{3})(\d{4})(\d{2})(\d{2})(\d{4})!$1/$2/$3/$4/$5!;
84 |
85 | $result->{ data }->{ appnum } = $appnum;
86 | }
87 |
88 | delete $result->{ data }->{ appointments }->{ $_ } for ( @{ $delete_fields->{ appointments } } );
89 |
90 | my $all_applicants = $self->query( 'selallkeys', __LINE__, "
91 | SELECT * FROM AutoAppData WHERE AppID = ?", $tables_id->{ AutoAppointments }
92 | );
93 |
94 | for my $app ( 0..$#$all_applicants ) {
95 |
96 | my $sch_app = {};
97 |
98 | if ( $all_applicants->[ $app ]->{ SchengenAppDataID } != 0 ) {
99 |
100 | $sch_app = $self->query( 'selallkeys', __LINE__, "
101 | SELECT * FROM AutoSchengenAppData WHERE ID = ?", $all_applicants->[ $app ]->{ SchengenAppDataID }
102 | )->[0];
103 |
104 | delete $sch_app->{ ID };
105 | }
106 |
107 | $result->{ data }->{ schengen }->[ $app ] = $sch_app;
108 |
109 | delete $all_applicants->[ $app ]->{ $_ } for ( @{ $delete_fields->{ appdata } } );
110 |
111 | $result->{ data }->{ appdata }->[ $app ] = $all_applicants->[ $app ];
112 | }
113 |
114 | return $result;
115 | }
116 |
117 | sub set_values_from_api
118 | # //////////////////////////////////////////////////
119 | {
120 | my $self = shift;
121 |
122 | my $enabled_fields_array = VCS::Site::autodata::get_mobile_api_fields();
123 |
124 | my $vars = $self->{ 'VCS::Vars' };
125 |
126 | my $json = $vars->getparam( 'data' );
127 |
128 | my $data = decode_json( $json );
129 |
130 | for my $table ( keys %{ $enabled_fields_array } ) {
131 |
132 | my %field_for_table = map { $_ => 1 } @{ $enabled_fields_array->{ $table } };
133 |
134 | if ( $table =~ /^(appdata|schengen)$/ ) {
135 |
136 | for my $app ( @{ $data->{ $table } } ) {
137 | for my $field ( keys %{ $app } ) {
138 | delete $app->{ $field } unless exists $field_for_table{ $field };
139 | }
140 | }
141 | }
142 | else {
143 | for my $field ( keys %{ $data->{ $table } } ) {
144 | delete $data->{ $table }->{ $field } unless exists $field_for_table{ $field };
145 | }
146 | }
147 | }
148 |
149 | my $app_id = $self->insert_hash_table( 'AutoAppointments', $data->{ appointments } );
150 |
151 | $self->query( 'query', __LINE__, "
152 | UPDATE AutoToken SET AutoAppID = ? WHERE Token = ?", {}, $app_id, $self->{ token }
153 | );
154 |
155 | my $app_max = 0;
156 |
157 | for ( 0..$#{ $data->{ appdata } } ) {
158 |
159 | my $sch_id = $self->insert_hash_table( 'AutoSchengenAppData', $data->{ schengen }->[ $_ ] );
160 |
161 | $data->{ appdata }->[ $_ ]->{ AppID } = $app_id;
162 | $data->{ appdata }->[ $_ ]->{ SchengenAppDataID } = $sch_id;
163 |
164 | $self->insert_hash_table( 'AutoAppData', $data->{ appdata }->[ $_ ] );
165 | }
166 |
167 | $self->redirect( $self->{ token } . '&mobile_app=on' );
168 | }
169 |
170 | sub get_api_centers
171 | # //////////////////////////////////////////////////
172 | {
173 | my $self = shift;
174 |
175 | my $result = {};
176 |
177 | my $all_centers = $self->query( 'selallkeys', __LINE__, "
178 | SELECT ID, BName, BAddr as address, phone, email, submissionTime, collectionTime
179 | FROM Branches
180 | WHERE isDeleted = 0 AND Display = 1"
181 | );
182 |
183 | my $geo_data = VCS::Site::autodata::get_geo_branches();
184 |
185 | for ( @$all_centers ) {
186 |
187 | $result->{ data }->{ $_->{ BName } } = $_;
188 |
189 | $result->{ data }->{ $_->{ BName } }->{ latitude } = $geo_data->{ $_->{ ID } }->[ 0 ];
190 |
191 | $result->{ data }->{ $_->{ BName } }->{ longitude } = $geo_data->{ $_->{ ID } }->[ 1 ];
192 |
193 | utf8::decode( $result->{ data }->{ $_->{ BName } }->{ address } );
194 |
195 | delete $result->{ data }->{ $_->{ BName } }->{ BName };
196 | }
197 |
198 | return $result;
199 | }
200 |
201 | sub get_doc_status
202 | # //////////////////////////////////////////////////
203 | {
204 | my $self = shift;
205 |
206 | my $result = {
207 | 'data' => {
208 | 'status' => "0"
209 | }
210 | };
211 |
212 | my $param = get_all_param( $self, 'docnum', 'birthdate' );
213 |
214 | $result->{ data }->{ docnum } = $param->{ docnum };
215 |
216 | return $result if !$param->{ docnum } or !$param->{ birthdate };
217 |
218 | my $docid = $self->query( 'sel1', __LINE__, "
219 | SELECT ID FROM DocPack WHERE AgreementNo = ? AND PStatus != 7",
220 | $param->{ docnum }
221 | ) || 0;
222 |
223 | return $result unless $docid;
224 |
225 | return $result unless $param->{ birthdate } =~ /^([0-9]{2})([0-9]{2})([0-9]{4})$/;
226 |
227 | my $birthdate = "$3-$2-$1";
228 |
229 | my $all_status = $self->query( 'selallkeys', __LINE__, "
230 | SELECT ApplID, Status, BthDate
231 | FROM DocPackInfo
232 | JOIN DocPackList ON DocPackInfo.ID = PackInfoID
233 | WHERE PackID = ?", $docid
234 | );
235 |
236 | for ( @$all_status ) {
237 |
238 | $result->{ data }->{ status } = $_->{ Status } if $birthdate eq $_->{ BthDate };
239 | }
240 |
241 | $result->{ data }->{ status } = "0" if $result->{ data }->{ status } == 7;
242 |
243 | $result->{ data }->{ status } = "3" if $result->{ data }->{ status } > 7;
244 |
245 | return $result;
246 | }
247 |
248 | sub get_advertisment
249 | # //////////////////////////////////////////////////
250 | {
251 | return { data => [ '' ] };
252 | }
253 |
254 | sub get_push
255 | # //////////////////////////////////////////////////
256 | {
257 | my ( $self, $swich ) = @_;
258 |
259 | my $result = get_api_head( $self, 2, 'without_token' );
260 |
261 | my $param = get_all_param( $self, 'docnum', 'mid', 'birthdate' );
262 |
263 | return $result if !$param->{ docnum } or !$param->{ mid } or !$param->{ birthdate };
264 |
265 | return $result unless $param->{ birthdate } =~ /^([0-9]{2})([0-9]{2})([0-9]{4})$/;
266 |
267 | my $birthdate = "$3-$2-$1";
268 |
269 | my $docid = $self->query( 'sel1', __LINE__, "
270 | SELECT DocPack.ID
271 | FROM DocPack
272 | JOIN DocPackInfo ON DocPack.ID = DocPackInfo.PackID
273 | JOIN DocPackList On DocPackInfo.ID = DocPackList.PackInfoID
274 | WHERE AgreementNo = ? AND DocPackList.BthDate = ? AND PStatus != 7",
275 | $param->{ docnum }, $birthdate
276 | );
277 |
278 | return get_api_head( $self, 3, 'without_token' ) unless $docid;
279 |
280 | $result = get_api_head( $self, 0, 'without_token' );
281 |
282 | my ( $pushid, $pushstatus ) = $self->query( 'sel1', __LINE__, "
283 | SELECT ID, PushStatus FROM DocPackMobilePush WHERE DocPackID = ? AND MobileID = ?",
284 | $docid, $param->{ mid }
285 | );
286 |
287 | if ( $swich =~ /on/i ) {
288 |
289 | $result->{ data }->{ push } = 'enabled';
290 |
291 | if ( !$pushid ) {
292 |
293 | $self->query( 'query', __LINE__, "
294 | INSERT INTO DocPackMobilePush (DocPackID, PushStatus, MobileID) VALUES (?, 1, ?)", {},
295 | $docid, $param->{ mid }
296 | );
297 | }
298 | elsif ( $pushstatus != 1 ) {
299 |
300 | $self->query( 'query', __LINE__, "
301 | UPDATE DocPackMobilePush SET PushStatus = 1 WHERE ID = ?", {},
302 | $pushid
303 | );
304 | }
305 | }
306 | else {
307 | $result->{ data }->{ push } = 'disabled';
308 |
309 | if ( $pushid and $pushstatus == 1 ) {
310 |
311 | $self->query( 'query', __LINE__, "
312 | UPDATE DocPackMobilePush SET PushStatus = 0 WHERE ID = ?", {},
313 | $pushid
314 | );
315 | }
316 | }
317 |
318 | return $result;
319 | }
320 |
321 | sub get_api_head
322 | # //////////////////////////////////////////////////
323 | {
324 | my ( $self, $error_number, $without_token ) = @_;
325 |
326 | my $error_text = [
327 | '',
328 | 'ошибка токена',
329 | 'ошибка API-запроса',
330 | 'договор не найден',
331 | 'у записи истёк срок действия',
332 | ];
333 |
334 | my $result = {
335 | 'error' => {
336 | 'error' => $error_number,
337 | 'error_text' => $self->lang( $error_text->[ $error_number ] ),
338 | }
339 | };
340 |
341 | $result->{ token } = $self->{ token } unless $without_token;
342 |
343 | return $result;
344 | }
345 |
346 | sub get_all_param
347 | # //////////////////////////////////////////////////
348 | {
349 | my $self = shift;
350 |
351 | my $param = {};
352 |
353 | for ( @_ ) {
354 |
355 | $param->{ $_ } = $self->{ vars }->getparam( $_ ) || '';
356 |
357 | $param->{ $_ } =~ s/[^0-9]//g unless $_ eq 'mid';
358 | }
359 |
360 | return $param;
361 | }
362 |
363 | 1;
364 |
--------------------------------------------------------------------------------
/autopayment.pm:
--------------------------------------------------------------------------------
1 | package VCS::Site::autopayment;
2 | use strict;
3 | use utf8;
4 |
5 | use LWP::UserAgent;
6 | use HTTP::Request;
7 | use Crypt::OpenSSL::RSA;
8 | use Data::Dumper;
9 | use Date::Calc;
10 | use JSON;
11 | use Encode qw(decode encode);
12 | use MIME::Base64;
13 |
14 | sub new
15 | # //////////////////////////////////////////////////
16 | {
17 | my ( $class, $pclass, $vars ) = @_;
18 |
19 | my $self = bless {}, $pclass;
20 |
21 | $self->{ 'VCS::Vars' } = $vars;
22 |
23 | return $self;
24 | }
25 |
26 | sub return_url
27 | # //////////////////////////////////////////////////
28 | {
29 |
30 | my $self = shift;
31 |
32 | return decode( 'utf8', $self->{ autoform }->{ payment }->{ back_url } . $self->{ autoform }->{ paths }->{ addr } . '?t=' . $self->{ token } );
33 | }
34 |
35 | sub payment
36 | # //////////////////////////////////////////////////
37 | {
38 |
39 | my ( $self, $order_number, $amount, $type ) = @_;
40 |
41 | my $config = VCS::Site::autodata::get_settings();
42 |
43 | my $amount_in_kopek = $amount * 100;
44 |
45 | my $data = {
46 | userName => $config->{ payment }->{ user_name },
47 | password => $config->{ payment }->{ password },
48 | orderNumber => $order_number,
49 | amount => $amount_in_kopek,
50 | returnUrl => return_url( $self ),
51 | };
52 |
53 | my $response = LWP::UserAgent->new( timeout => 30 )->post( join( '/', $config->{ payment }->{ url } , 'register.do' ), $data );
54 |
55 | return ( undef, undef ) unless $response->is_success;
56 |
57 | my $payment = JSON->new->pretty->decode( $response->decoded_content );
58 |
59 | return ( $payment->{ orderId }, $payment->{ formUrl } );
60 | }
61 |
62 | sub status
63 | # //////////////////////////////////////////////////
64 | {
65 |
66 | my ( $self, $order_id, $type ) = @_;
67 |
68 | my $config = VCS::Site::autodata::get_settings();
69 |
70 | my $data = {
71 | userName => $config->{ payment }->{ user_name },
72 | password => $config->{ payment }->{ password },
73 | orderId => $order_id,
74 | };
75 |
76 | my $response = LWP::UserAgent->new(timeout => 30)->post( join( '/', $config->{ payment }->{ url }, 'getOrderStatus.do' ), $data );
77 |
78 | return -1 unless $response->is_success;
79 |
80 | my $status = JSON->new->pretty->decode( $response->decoded_content );
81 |
82 | $status->{ OrderStatus } =~ s/[^0-9]+//g;
83 |
84 | return $status->{ OrderStatus };
85 | }
86 |
87 | sub cloud_payment
88 | # //////////////////////////////////////////////////
89 | {
90 |
91 | my ( $self, $data ) = @_;
92 |
93 | my $config = VCS::Site::autodata::get_settings();
94 |
95 | my $ua = LWP::UserAgent->new( timeout => 30 );
96 |
97 | $ua->ssl_opts(
98 | SSL_cert_file => $config->{ cloud }->{ ssl_cert },
99 | SSL_key_file => $config->{ cloud }->{ ssl_key },
100 | SSL_passwd_cb => sub { return $config->{ cloud }->{ ssl_pwd }; }
101 | );
102 |
103 | my $content = encode( 'utf8', JSON->new->pretty->encode( $data ) );
104 |
105 | my $request = HTTP::Request->new( 'POST', $config->{ cloud }->{ url } );
106 |
107 | $request->header('Content-Type' => 'application/json');
108 |
109 | $request->header('X-Signature' => signature( $content ) );
110 |
111 | $request->content( $content );
112 |
113 | my $response = $ua->request( $request );
114 |
115 | my $responses = {
116 | 201 => "OK",
117 | 401 => "ERROR: certificate",
118 | 409 => "ERROR: duplicate",
119 | 400 => "ERROR: validation",
120 | 503 => "ERROR: queue",
121 | };
122 |
123 | my $response_line = $responses->{ $response->{ _rc } };
124 |
125 | return ($response_line ? $response_line : "ERROR: unknown type (" . $response->{ _rc } . ")" );
126 | }
127 |
128 | sub cloud_status
129 | # //////////////////////////////////////////////////
130 | {
131 |
132 | my ( $self, $company, $docid ) = @_;
133 |
134 | my $config = VCS::Site::autodata::get_settings();
135 |
136 | my $ua = LWP::UserAgent->new( timeout => 30 );
137 |
138 | $ua->ssl_opts(
139 | SSL_cert_file => $config->{ cloud }->{ ssl_cert },
140 | SSL_key_file => $config->{ cloud }->{ ssl_key },
141 | SSL_passwd_cb => sub { return $config->{ cloud }->{ ssl_pwd }; }
142 | );
143 |
144 | my $response = $ua->get( $config->{ cloud }->{ url } . "$company/status/$docid" );
145 |
146 | return $response->{ _rc };
147 | }
148 |
149 | sub signature
150 | # //////////////////////////////////////////////////
151 | {
152 | my $data = shift;
153 |
154 | my $config = VCS::Site::autodata::get_settings();
155 |
156 | open( my $file, '<', $config->{ cloud }->{ rsa_key } ) or return;
157 |
158 | my $key_string;
159 |
160 | $key_string .= $_ while <$file>;
161 |
162 | close $file;
163 |
164 | my $rsa = Crypt::OpenSSL::RSA->new_private_key( $key_string );
165 |
166 | $rsa->use_pkcs1_padding();
167 |
168 | $rsa->use_sha256_hash();
169 |
170 | return encode_base64( $rsa->sign( $data ) );
171 | }
172 |
173 | sub fox_pay_status_req
174 | # //////////////////////////////////////////////////
175 | {
176 | my ( $self, $order_number ) = @_;
177 |
178 | my $config = VCS::Site::autodata::get_settings();
179 |
180 | my $response = LWP::UserAgent->new( timeout => 30 )->get( $config->{ fox }->{ pay_status } . $order_number );
181 |
182 | return 0 unless $response->is_success;
183 |
184 | my $result = decode( 'utf8', $response->{ _content } );
185 |
186 | return ( $result =~ /Документ\s+$order_number\s+оплачен/i ? 1 : 0 );
187 | }
188 |
189 | sub fox_pay_status
190 | # //////////////////////////////////////////////////
191 | {
192 | my ( $self, $order_number_from, $order_number_to ) = @_;
193 |
194 | my $form_payment_ok = fox_pay_status_req( $self, $order_number_from );
195 |
196 | my $to_payment_ok = fox_pay_status_req( $self, $order_number_to );
197 |
198 | return $form_payment_ok && $to_payment_ok;
199 | }
200 |
201 | sub fox_pay_document
202 | # //////////////////////////////////////////////////
203 | {
204 | my ( $self, $order_number ) = @_;
205 |
206 | my $config = VCS::Site::autodata::get_settings();
207 |
208 | my $url_param = "login=" . $config->{ fox }->{ login } . "&password=" . $config->{ fox }->{ password } .
209 | "&documentType=order&number=" . $order_number . "&numberType=internalnumber&formName=Накладная";
210 |
211 | my $response = LWP::UserAgent->new( timeout => 30 )->get( $config->{ fox }->{ document } . $url_param );
212 |
213 | return "" unless $response->is_success;
214 |
215 | my $content = JSON->new->pretty->decode( $response->decoded_content );
216 |
217 | my $document = $content->{ List }->[ 0 ]->{ BData }->[ 0 ];
218 |
219 | return decode_base64($document)
220 | }
221 |
222 | sub fox_status
223 | # //////////////////////////////////////////////////
224 | {
225 | my ( $self, $order_number_from, $order_number_to ) = @_;
226 |
227 | my $config = VCS::Site::autodata::get_settings();
228 |
229 | my $url_param = "login=" . $config->{ fox }->{ login } . "&password=" . $config->{ fox }->{ password } .
230 | "&documentType=order&number=" . $order_number_from;
231 |
232 | my $response = LWP::UserAgent->new( timeout => 30 )->get( $config->{ fox }->{ track } . $url_param );
233 |
234 | return "" unless $response->is_success;
235 |
236 | my $status = JSON->new->pretty->decode( $response->decoded_content );
237 |
238 | my $line = "";
239 |
240 | $line = $status->{ documents }->[ 0 ]->{ history }->[ -1 ]->{ eventState }
241 | if ( length( $status->{ documents }->[ 0 ]->{ history } ) > 0 );
242 |
243 | return $line;
244 | }
245 |
246 | 1;
--------------------------------------------------------------------------------
/autosms.pm:
--------------------------------------------------------------------------------
1 | package VCS::Site::autosms;
2 | use strict;
3 | use utf8;
4 |
5 | use Math::Random::Secure qw( irand );
6 | use Digest::MD5 qw( md5_hex );
7 | use Digest::SHA1 qw( sha1_hex );
8 | use HTTP::Request::Common;
9 | use Data::Dumper;
10 |
11 | sub new
12 | # //////////////////////////////////////////////////
13 | {
14 | my ( $class, $pclass, $vars ) = @_;
15 |
16 | my $self = bless {}, $pclass;
17 |
18 | $self->{ 'VCS::Vars' } = $vars;
19 |
20 | return $self;
21 | }
22 |
23 | sub get_phone_for_sms
24 | # //////////////////////////////////////////////////
25 | {
26 | my ( $self, $without_app ) = @_;
27 |
28 | my $phone = undef;
29 |
30 | if ( $without_app ) {
31 |
32 | my ( $app_phone, $appdata_phone ) = $self->{ af }->query( 'sel1', __LINE__, "
33 | SELECT AutoAppointments.Phone, AutoAppData.AppPhone
34 | FROM AutoToken
35 | JOIN AutoAppointments ON AutoToken.AutoAppID = AutoAppointments.ID
36 | LEFT JOIN AutoAppData ON AutoToken.AutoAppDataID = AutoAppData.ID
37 | WHERE Token = ?", $self->{ token }
38 | );
39 |
40 | $phone = ( !$appdata_phone ? $app_phone : $appdata_phone );
41 | }
42 | else {
43 | $phone = $self->{ af }->query( 'sel1', __LINE__, "
44 | SELECT Phone FROM Appointments JOIN AutoToken ON Appointments.ID = AutoToken.CreatedApp
45 | WHERE AutoToken.Token = ?", $self->{ token }
46 | );
47 | }
48 |
49 | return $phone;
50 | }
51 |
52 | sub get_code_from_db
53 | # //////////////////////////////////////////////////
54 | {
55 | my ( $self, $without_app ) = @_;
56 |
57 | my ( $remote_id, $sms_code ) = ( 0, 0 );
58 |
59 | if ( $without_app ) {
60 |
61 | ( $remote_id, $sms_code ) = $self->{ af }->query( 'sel1', __LINE__, "
62 | SELECT DocUploadedAgreements.ID, SMScode FROM DocUploadedAgreements
63 | JOIN AutoToken ON AutoToken.ID = DocUploadedAgreements.Token
64 | WHERE AutoToken.Token = ?", $self->{ token }
65 | );
66 | }
67 | else {
68 | ( $remote_id, $sms_code ) = $self->{ af }->query( 'sel1', __LINE__, "
69 | SELECT AutoRemote.ID, SMScode FROM AutoRemote
70 | JOIN AutoToken ON AutoToken.CreatedApp = AutoRemote.AppID
71 | WHERE Token = ?", $self->{ token }
72 | );
73 | }
74 |
75 | return ( $remote_id, $sms_code );
76 | }
77 |
78 | sub get_code_for_sms
79 | # //////////////////////////////////////////////////
80 | {
81 | my ( $self, $phone, $without_app ) = @_;
82 |
83 | my $config = VCS::Site::autodata::get_settings()->{ sms };
84 |
85 | my ( $remote_id, $sms_code ) = get_code_from_db( $self, $without_app );
86 |
87 | return md5_hex( $sms_code ) if $sms_code;
88 |
89 | my $new_code = int( irand( 9000 ) ) + 1000;
90 |
91 | my $sms_id = 0;
92 |
93 | $sms_id = sending_sms( $self, $phone, "Vash kod dogovora $new_code" ) unless $config->{ do_not_send_sms };
94 |
95 | my $table = ( $without_app ? "DocUploadedAgreements" : "AutoRemote" );
96 |
97 | $self->{ af }->query( 'query', __LINE__, "
98 | UPDATE $table SET SMScode = ?, SMSmsgID = ? WHERE ID = ?", {}, $new_code, $sms_id, $remote_id
99 | );
100 |
101 | return md5_hex( $new_code );
102 | }
103 |
104 | sub get_signed
105 | # //////////////////////////////////////////////////
106 | {
107 | my $self = shift;
108 |
109 | my $sign_date = $self->query( 'sel1', __LINE__, "
110 | SELECT SMSsigned FROM DocUploadedAgreements
111 | JOIN AutoToken ON AutoToken.ID = DocUploadedAgreements.Token
112 | WHERE AutoToken.Token = ?", $self->{ token }
113 | );
114 |
115 | return $sign_date;
116 | }
117 |
118 | sub code_from_sms_is_ok
119 | # //////////////////////////////////////////////////
120 | {
121 | my ( $self, $code, $without_app ) = @_;
122 |
123 | my ( $remote_id, $sms_code ) = get_code_from_db( $self, $without_app );
124 |
125 | return 0 unless $sms_code eq $code;
126 |
127 | my $table = ( $without_app ? "DocUploadedAgreements" : "AutoRemote" );
128 |
129 | $self->{ af }->query( 'query', __LINE__, "
130 | UPDATE $table SET SMSsigned = now() WHERE ID = ?", {}, $remote_id
131 | );
132 |
133 |
134 | return 1;
135 | }
136 |
137 | sub sending_sms
138 | # //////////////////////////////////////////////////
139 | {
140 | my ( $self, $phone, $message ) = @_;
141 |
142 | my $sms = VCS::Site::autodata::get_settings()->{ sms };
143 |
144 | my $sms_sign = join( ';', sort ( $sms->{ project }, $sms->{ sender }, $message, $phone ) ) . ';' . $sms->{ key };
145 |
146 | $sms_sign = md5_hex( sha1_hex( $sms_sign ) );
147 |
148 | my $ua = LWP::UserAgent->new;
149 |
150 | $ua->agent('Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 7.60');
151 |
152 | my $request_url = $sms->{ send_url } . '?project=' . $sms->{ project } . '&sender=' . $sms->{ sender } .
153 | '&message=' . $message . '&recipients=' . $phone . '&sign=' . $sms_sign;
154 |
155 | my $response = LWP::UserAgent->new( timeout => 30 )->get( $request_url );
156 |
157 | return 0 unless $response->is_success;
158 |
159 | return 0 unless $response->content =~ /\"status\"\:\"success\"/;
160 |
161 | return 0 unless $response->content =~ /\"messages\_id\"\:\[([0-9]+)\]/;
162 |
163 | return $1;
164 | }
165 |
166 | 1;
--------------------------------------------------------------------------------
/css/autoform.css:
--------------------------------------------------------------------------------
1 |
2 | .left{
3 | text-align: left;
4 | }
5 |
6 | .center {
7 | text-align: center;
8 | }
9 |
10 | .centered {
11 | margin: 0 auto;
12 | }
13 |
14 | .bottom{
15 | vertical-align: bottom;
16 | }
17 |
18 | .progressbar_gen{
19 | display:none;
20 | border-collapse:collapse;
21 | width:100%;
22 | }
23 |
24 | .pr_size_gen{
25 | background-size: 100% 100%;
26 | }
27 |
28 | .pr_red_red_gen{ background-image: url('/vcs/static/images/pbar-red-red.png'); }
29 | .pr_red_gray_gen{ background-image: url('/vcs/static/images/pbar-red-gray.png'); }
30 | .pr_red_white_gen{ background-image: url('/vcs/static/images/pbar-red-white.png'); }
31 | .pr_gray_gray_gen{ background-image: url('/vcs/static/images/pbar-gray-gray.png'); }
32 | .pr_gray_white_gen{ background-image: url('/vcs/static/images/pbar-gray-white.png'); }
33 | .pr_white_red_gen{ background-image: url('/vcs/static/images/pbar-white-red.png'); }
34 | .pr_white_gray_gen{ background-image: url('/vcs/static/images/pbar-white-gray.png'); }
35 |
36 | .pr_in_gen{
37 | color:white;
38 | font-size:33px;
39 | line-height: 51px
40 | }
41 |
42 | .big_progr{
43 | width:50px;
44 | height:50px;
45 | border-radius:25px;
46 | }
47 |
48 | .ltl_progr{
49 | width:18px;
50 | height:18px;
51 | border-radius:9px;
52 | }
53 |
54 | .pr_past{
55 | background:#FF6666;
56 | }
57 |
58 | .pr_current{
59 | background:#CC0033;
60 | }
61 |
62 | .pr_future{
63 | background:#999999;
64 | }
65 |
66 | .input_gen{
67 | width:20em;
68 | }
69 |
70 | .exam_td_gen{
71 | vertical-align:top;
72 | }
73 |
74 | .exam_span_gen{
75 | color:gray;
76 | font-size:0.7em;
77 | }
78 |
79 | .stage_gen{
80 | padding:5px;
81 | text-align:center;
82 | }
83 |
84 | .dotted_link{
85 | color:#999999;
86 | font-size:12px;
87 | font-weight:normal;
88 | border-bottom:1px dotted #999999;
89 | text-decoration:none;
90 | }
91 |
92 | .dotted_link_middle{
93 | color:#999999;
94 | font-weight:normal;
95 | border-bottom:1px dotted #999999;
96 | text-decoration:none;
97 | }
98 |
99 | .dotted_link_big{
100 | color:#FF6666;
101 | font-weight:normal;
102 | border-bottom:1px dotted #DB121A;
103 | text-decoration:none;
104 | }
105 |
106 | .nfc_link{
107 | text-decoration:none;
108 | color:#666666;
109 | }
110 |
111 | .optional_field{
112 | background-color:#F5F5F5;
113 | border-width:1px;
114 | }
115 |
116 | .bold_text{
117 | font-weight:bold;
118 | }
119 |
120 | .post_index{
121 | font-size:14px;
122 | color:#FF6666;
123 | }
124 |
125 | .ltl_text{
126 | font-size:12px;
127 | color:#999999;
128 | font-weight:normal;
129 | }
130 |
131 | .ltl_link{
132 | font-size:12px;
133 | color:#999999;
134 | font-weight:normal;
135 | border-bottom: 1px dotted #999999;
136 | cursor:pointer;
137 | }
138 |
139 | .big_button{
140 | width:100%;
141 | height:40px;
142 | margin-bottom:2px
143 | }
144 |
145 | .button_spacer{
146 | margin-top:8px;
147 | }
148 |
149 | .finish_text_spacer{
150 | margin-bottom:0px;
151 | margin-top:8px;
152 | }
153 |
154 | .small_button{
155 | height:25px;
156 | }
157 |
158 | .info_list{
159 | overflow:hidden;
160 | width:280px;
161 | max-width:280px;
162 | text-overflow:ellipsis;
163 | }
164 |
165 | .optional_line{
166 | color:gray;
167 | }
168 |
169 | .m_right{
170 | text-align:right;
171 | }
172 |
173 | .m_right_m{
174 | text-align:right;
175 | white-space: nowrap;
176 | }
177 |
178 | .dashed_line{
179 | border-bottom: 1px dashed #999999;
180 | }
181 |
182 | .width_full{
183 | width:100%;
184 | }
185 |
186 | .width_small{
187 | width:5%;
188 | }
189 |
190 | .margin_big{
191 | margin:50px;
192 | }
193 |
194 | .yandex_map{
195 | width:100%;
196 | height:400px;
197 | }
198 |
199 | .captcha_container {
200 | width:100%;
201 | }
202 |
203 | .g-recaptcha {
204 | transform-origin: left top;
205 | -webkit-transform-origin: left top;
206 | }
207 |
208 | .suppl_text {
209 | color:#585858;
210 | }
211 |
212 | .grayborder {
213 | border-collapse:collapse;
214 | border:1px solid #D3D3D3;
215 | padding:10px;
216 | }
217 |
218 | .biometric_box{
219 | padding-top:10px;
220 | padding-bottom:5px;
221 | border-bottom-width:1px;
222 | border-bottom-color:red;
223 | border-bottom-style:solid;
224 | border-top-width:1px;
225 | border-top-color:red;
226 | border-top-style:solid;
227 | }
228 |
229 | .biometric_right {
230 | font-size:15px;
231 | color:#666666;
232 | padding:0px;
233 | display:inline-block;
234 | }
235 |
236 | .biometric_left {
237 | display:inline;
238 | height:37px;
239 | }
240 |
241 | .biometric_left_inner {
242 | height:37px;
243 | display:table-cell;
244 | vertical-align:middle;
245 | text-align:center;
246 | }
247 |
248 | .disclaimer {
249 | border:1px solid black;
250 | display:none;
251 | padding:15px;
252 | font-size:9px;
253 | text-align:justify;
254 | }
255 |
256 | .oferta {
257 | border:1px solid black;
258 | padding:15px;
259 | font-size:9px;
260 | text-align:justify;
261 | }
262 |
263 | .editFullOption {
264 | border:1px solid gray;
265 | padding:15px;
266 | font-size:12px;
267 | font-color:gray;
268 | text-align:justify;
269 | }
270 | .editFullBlock {
271 | border:1px solid black;
272 | display:none;
273 | padding:15px;
274 | font-size:12px;
275 | text-align:justify;
276 | }
277 |
278 | .no_border {
279 | border: none;
280 | border-spacing: 0;
281 | border-collanse: collapse;
282 | }
283 |
284 | .add_info_text{
285 | font-size:11px;
286 | font-weight:normal;
287 | }
288 |
289 | .gray_line{
290 | border: 1px solid #D3D3D3;
291 | }
292 |
293 | .hidden {
294 | display:none;
295 | }
296 |
297 | .pc_hide {
298 | display:none;
299 | height:40px;
300 | text-align:center;
301 | vertical-align:bottom;
302 | padding-bottom:3px;
303 | }
304 |
305 | .pc_hide_line {
306 | display:none;
307 | text-align:center;
308 | vertical-align:bottom;
309 | font-weight:bold;
310 | text-transform:uppercase;
311 | }
312 |
313 | .middle {
314 | vertical-align:middle;
315 | }
316 |
317 | .uplsuccess {
318 | color: green;
319 | font-size:25px;
320 | line-height: 0.8;
321 | }
322 |
323 | .nope_doc {
324 | color:gray;
325 | }
326 |
327 | .ok_doc {
328 | color:green;
329 | }
330 |
331 | .err_doc {
332 | color:red;
333 | font-weight:bold;
334 | }
335 |
336 | .insist_doc {
337 | color:blue;
338 | }
339 |
340 | .doc_support_comment {
341 | display:inline-block;
342 | margin-left:20px;
343 | padding:10px;
344 | border-collapse:collapse;
345 | background-color:#FFCCCC;
346 | font-size:11px;
347 | }
348 |
349 | .log_comment {
350 | display:inline-block;
351 | margin-left:20px;
352 | padding:10px;
353 | border-collapse:collapse;
354 | background-color:#CCCCCC;
355 | font-size:11px;
356 | }
357 |
358 | .doc_app_comment {
359 | display:inline-block;
360 | margin-left:20px;
361 | padding:10px;
362 | border-collapse:collapse;
363 | background-color:#6699FF;
364 | font-size:11px;
365 | }
366 |
367 | .show_comment {
368 | display:inline-block;
369 | margin-left:20px;
370 | color:red;
371 | font-weight:bold;
372 | cursor:pointer;
373 | }
374 |
375 | .show_replace_option {
376 | display:inline-block;
377 | margin-left:20px;
378 | }
379 |
380 | .show_other_option {
381 | display:inline-block;
382 | }
383 |
384 | .add_comment {
385 | display:inline-block;
386 | margin-left:20px;
387 | color:black;
388 | font-size:10px;
389 | }
390 |
391 | .add_comment_block {
392 | display:inline-block;
393 | margin-left:20;
394 | }
395 |
396 | .very_important {
397 | color:red;
398 | font-weight:bold;
399 | }
400 |
401 | .files_uploaded {
402 | font-size:12px;
403 | }
--------------------------------------------------------------------------------
/css/tip-redsimple.css:
--------------------------------------------------------------------------------
1 | .tip-redsimple {
2 | z-index:1000;
3 | text-align:left;
4 | border:1px solid #CC0033;
5 | border-radius:4px;
6 | -moz-border-radius:4px;
7 | -webkit-border-radius:4px;
8 | padding:6px 8px;
9 | min-width:50px;
10 | max-width:300px;
11 | color:#FFFFFF;
12 | background-color:#CC0033;
13 | }
14 | .tip-redsimple .tip-inner {
15 | font:12px/16px arial,helvetica,sans-serif;
16 | line-height:1.2;
17 | }
18 |
19 | .tip-redsimple .tip-arrow-top {
20 | margin-top:-6px;
21 | margin-left:-5px;
22 | top:0;
23 | left:50%;
24 | width:9px;
25 | height:6px;
26 | background:url(tip-redsimple_arrows.gif) no-repeat;
27 | }
28 | .tip-redsimple .tip-arrow-right {
29 | margin-top:-4px;
30 | margin-left:0;
31 | top:50%;
32 | left:100%;
33 | width:6px;
34 | height:9px;
35 | background:url(tip-redsimple_arrows.gif) no-repeat -9px 0;
36 | }
37 | .tip-redsimple .tip-arrow-bottom {
38 | margin-top:0;
39 | margin-left:-5px;
40 | top:100%;
41 | left:50%;
42 | width:9px;
43 | height:6px;
44 | background:url(tip-redsimple_arrows.gif) no-repeat -18px 0;
45 | }
46 | .tip-redsimple .tip-arrow-left {
47 | margin-top:-4px;
48 | margin-left:-6px;
49 | top:50%;
50 | left:0;
51 | width:6px;
52 | height:9px;
53 | background:url(tip-redsimple_arrows.gif) no-repeat -27px 0;
54 | }
--------------------------------------------------------------------------------
/css/tip-yellowsimple.css:
--------------------------------------------------------------------------------
1 | .tip-yellowsimple {
2 | z-index:1000;
3 | text-align:left;
4 | border:1px solid #c7bf93;
5 | border-radius:4px;
6 | -moz-border-radius:4px;
7 | -webkit-border-radius:4px;
8 | padding:6px 8px;
9 | min-width:50px;
10 | max-width:300px;
11 | color:#000;
12 | background-color:#fff9c9;
13 | }
14 | .tip-yellowsimple .tip-inner {
15 | font:12px/16px arial,helvetica,sans-serif;
16 | line-height:1.2;
17 | }
18 |
19 | .tip-yellowsimple .tip-arrow-top {
20 | margin-top:-6px;
21 | margin-left:-5px;
22 | top:0;
23 | left:50%;
24 | width:9px;
25 | height:6px;
26 | background:url(tip-yellowsimple_arrows.gif) no-repeat;
27 | }
28 | .tip-yellowsimple .tip-arrow-right {
29 | margin-top:-4px;
30 | margin-left:0;
31 | top:50%;
32 | left:100%;
33 | width:6px;
34 | height:9px;
35 | background:url(tip-yellowsimple_arrows.gif) no-repeat -9px 0;
36 | }
37 | .tip-yellowsimple .tip-arrow-bottom {
38 | margin-top:0;
39 | margin-left:-5px;
40 | top:100%;
41 | left:50%;
42 | width:9px;
43 | height:6px;
44 | background:url(tip-yellowsimple_arrows.gif) no-repeat -18px 0;
45 | }
46 | .tip-yellowsimple .tip-arrow-left {
47 | margin-top:-4px;
48 | margin-left:-6px;
49 | top:50%;
50 | left:0;
51 | width:6px;
52 | height:9px;
53 | background:url(tip-yellowsimple_arrows.gif) no-repeat -27px 0;
54 | }
--------------------------------------------------------------------------------
/images/1x1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/1x1.png
--------------------------------------------------------------------------------
/images/app-helper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/app-helper.png
--------------------------------------------------------------------------------
/images/autoform_wait.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/autoform_wait.gif
--------------------------------------------------------------------------------
/images/biometric_pass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/biometric_pass.png
--------------------------------------------------------------------------------
/images/pbar-gray-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/pbar-gray-gray.png
--------------------------------------------------------------------------------
/images/pbar-gray-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/pbar-gray-white.png
--------------------------------------------------------------------------------
/images/pbar-red-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/pbar-red-gray.png
--------------------------------------------------------------------------------
/images/pbar-red-red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/pbar-red-red.png
--------------------------------------------------------------------------------
/images/pbar-red-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/pbar-red-white.png
--------------------------------------------------------------------------------
/images/pbar-white-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/pbar-white-gray.png
--------------------------------------------------------------------------------
/images/pbar-white-red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/pbar-white-red.png
--------------------------------------------------------------------------------
/images/tip-redsimple_arrows.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/tip-redsimple_arrows.gif
--------------------------------------------------------------------------------
/images/tip-yellowsimple_arrows.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/tip-yellowsimple_arrows.gif
--------------------------------------------------------------------------------
/images/type_jpg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/type_jpg.png
--------------------------------------------------------------------------------
/images/type_pdf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/type_pdf.png
--------------------------------------------------------------------------------
/images/type_png.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/type_png.png
--------------------------------------------------------------------------------
/images/type_tiff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/type_tiff.png
--------------------------------------------------------------------------------
/images/type_unk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mig1023/autoform/13110f916a90a6679e614cffe18b8c6a9958a073/images/type_unk.png
--------------------------------------------------------------------------------
/model/autodata_type_d.pm:
--------------------------------------------------------------------------------
1 | package VCS::Site::autodata_type_d;
2 | use strict;
3 |
4 | sub get_progressline
5 | # //////////////////////////////////////////////////
6 | {
7 | return [ '',
8 | { big => 1, name => 'Начало', },
9 | { big => 0, name => 'Даты поездки', },
10 | { big => 1, name => 'Заявители', },
11 | { big => 0, name => 'Данные паспорта', },
12 | { big => 0, name => 'Данные загранпаспорта', },
13 | { big => 1, name => 'Оформление', },
14 | { big => 0, name => 'Данные для договора', },
15 | { big => 0, name => 'Выбор даты записи', },
16 | { big => 0, name => 'Офис выдачи', },
17 | { big => 0, name => 'Подтверждение', },
18 | { big => 1, name => 'Готово!', },
19 | ];
20 | }
21 |
22 | sub get_content_rules_hash
23 | # //////////////////////////////////////////////////
24 | {
25 |
26 | my $standart_date_check = 'zD^(([012]\d|3[01])\.((0\d)|(1[012]))\.(19\d\d|20[0-3]\d))$';
27 |
28 | return {
29 |
30 | 'Начало записи' => [
31 | {
32 | page_ord => 100,
33 | progress => 1,
34 | param => 1,
35 | goto_link => 'to_start',
36 | page_db_id => 300001,
37 | },
38 | {
39 | type => 'select',
40 | name => 'center',
41 | label => 'Визовый центр',
42 | comment => 'Выберите визовый центр для подачи документов',
43 | check => 'zN',
44 | db => {
45 | table => 'Appointments',
46 | name => 'CenterID',
47 | },
48 | param => '[centers_from_db]',
49 | uniq_code => 'onchange="update_nearest_date_free_date();"',
50 | first_elements => 'default_free, 1, 44, 41',
51 | special => 'cach_this_value',
52 | },
53 | {
54 | type => 'select',
55 | name => 'vtype',
56 | label => 'Тип визы',
57 | comment => 'Выберите тип запрашиваемой визы',
58 | check => 'zN',
59 | db => {
60 | table => 'Appointments',
61 | name => 'VType',
62 | },
63 | param => '[visas_from_db]',
64 | first_elements => '13',
65 | special => 'cach_this_value',
66 | },
67 | {
68 | type => 'input',
69 | name => 'num_of_person',
70 | label => 'Количество заявителей',
71 | comment => 'Укажите количество человек, запрашивающих визу',
72 | example => '1',
73 | check => 'zN',
74 | uniq_code => 'onkeyup="update_nearest_date_free_date(1);"',
75 | check_logic => [
76 | {
77 | condition => 'less_than',
78 | offset => '40',
79 | },
80 | ],
81 | db => {
82 | table => 'Appointments',
83 | name => 'NCount',
84 | },
85 | },
86 | {
87 | type => 'free_line',
88 | },
89 | {
90 | type => 'info',
91 | name => 'free_date',
92 | label => 'Ближайшая доступная дата',
93 | comment => 'Вы сможете выбрать удобную для Вас дату подачи документов во время оформления записи',
94 | special => 'nearest_date',
95 | },
96 | {
97 | type => 'free_line',
98 | },
99 | {
100 | type => 'input',
101 | name => 'email',
102 | label => 'Email',
103 | comment => 'Введите существующий адрес почты. На него будет выслано подтверждение записи в визовый центр. Пожалуйста, проверьте правильность каждой буквы/символа, из которых состоит адрес Вашей электронной почты',
104 | example => 'info@example.ru',
105 | check => 'zWN\@\-\_\.',
106 | check_logic => [
107 | {
108 | condition => 'this_is_email',
109 | },
110 | {
111 | condition => 'email_not_blocked',
112 | },
113 | ],
114 | db => {
115 | table => 'Appointments',
116 | name => 'EMail',
117 | },
118 | },
119 | {
120 | type => 'input',
121 | name => 'emailcheck',
122 | label => 'Подтвердите email',
123 | comment => 'Обратите внимание, что адрес электронной почты необходимо вводить вручную, не копируя его из предыдущего поля. Это поможет Вам избежать ошибки и возможной отправки подтверждения Вашей записи не тому адресату. ',
124 | example => 'info@example.ru',
125 | check => 'zWN\@\-\_\.',
126 | check_logic => [
127 | {
128 | condition => 'equal',
129 | table => 'Appointments',
130 | name => 'EMail',
131 | full_error => 'EMail не совпадает с подтверждением',
132 | },
133 | ],
134 | db => {
135 | table => 'AutoToken',
136 | name => 'EMail',
137 | },
138 | special => 'no_copypast',
139 | },
140 | {
141 | type => 'free_line',
142 | },
143 | {
144 | type => 'disclaimer',
145 | name => 'pers_info',
146 | label_for => 'я согласен с условиями обработки персональных данных визовым центром',
147 | comment => 'disclaimer_text',
148 | check => 'true',
149 | full_line => 1,
150 | db => {
151 | table => 'Appointments',
152 | name => 'PersonalDataPermission',
153 | transfer => 'nope',
154 | },
155 | },
156 | {
157 | type => 'checkbox',
158 | name => 'mobil_info',
159 | label_for => 'я уведомлён о том, что на территории Визового центра запрещается пользоваться электронными мобильными устройствами',
160 | check => 'true',
161 | full_line => 1,
162 | db => {
163 | table => 'Appointments',
164 | name => 'MobilPermission',
165 | transfer => 'nope',
166 | },
167 | relation => {},
168 | },
169 | {
170 | type => 'include',
171 | place => 'out',
172 | template => 'vip_form.tt2',
173 | },
174 | ],
175 |
176 | 'Даты поездки' => [
177 | {
178 | page_ord => 200,
179 | progress => 2,
180 | collect_date => 1,
181 | page_db_id => 300002,
182 | },
183 | {
184 | type => 'input',
185 | name => 's_date',
186 | label => 'Дата начала поездки',
187 | comment => 'Введите предполагаемую дату начала поездки',
188 | example => '31.12.1900',
189 | check => $standart_date_check,
190 | check_logic => [
191 | {
192 | condition => 'now_or_later',
193 | offset => '[collect_date_offset]',
194 | },
195 | {
196 | condition => 'now_or_earlier',
197 | offset => 180,
198 | equality_is_also_fail => 1,
199 | full_error => 'Действует ограничение на максимальную дату вылета: не более [offset] с текущей даты',
200 | },
201 | ],
202 | db => {
203 | table => 'Appointments',
204 | name => 'SDate',
205 | },
206 | special => 'datepicker, mask',
207 | minimal_date => 'current',
208 | },
209 | {
210 | type => 'input',
211 | name => 'f_date',
212 | label => 'Дата окончания поездки',
213 | comment => 'Введите предполагаемую дату окончания поездки',
214 | example => '31.12.1900',
215 | check => $standart_date_check,
216 | check_logic => [
217 | {
218 | condition => 'equal_or_later',
219 | table => 'Appointments',
220 | name => 'SDate',
221 | error => 'Дата начала поездки',
222 | },
223 | ],
224 | db => {
225 | table => 'Appointments',
226 | name => 'FDate',
227 | },
228 | special => 'datepicker, mask',
229 | minimal_date => 's_date',
230 | },
231 | ],
232 |
233 | 'Список заявителей' => [
234 | {
235 | page_ord => 300,
236 | progress => 3,
237 | goto_link => 'back_to_appdata',
238 | all_app_in_title => 1,
239 | replacer => '[list_of_applicants]',
240 | page_db_id => 300003,
241 | },
242 | ],
243 |
244 | 'Данные паспорта' => [
245 | {
246 | page_ord => 400,
247 | progress => 4,
248 | all_app_in_title => 1,
249 | param => 1,
250 | page_db_id => 300004,
251 | },
252 | {
253 | type => 'select',
254 | name => 'сitizenship',
255 | label => 'Гражданство в настоящее время',
256 | comment => 'Если у вас два гражданства, то укажите гражданство по паспорту той страны, который подаёте на визу',
257 | example => 'The Russian Federation',
258 | check => 'zN',
259 | db => {
260 | table => 'AppData',
261 | name => 'Citizenship',
262 | },
263 | param => '[citizenship_countries]',
264 | first_elements => '70',
265 | },
266 | {
267 | type => 'free_line',
268 | },
269 | {
270 | type => 'input',
271 | name => 'rulname',
272 | label => 'Фамилия',
273 | comment => 'Введите фамилию на русском языке так, как она указана во внутреннем паспорте',
274 | example => 'Петров',
275 | check => 'zWЁ\s\-',
276 | check_logic => [
277 | {
278 | condition => 'english_only_for_not_rf_citizen',
279 | full_error => 'Для граждан РФ фамилию необходимо вводить на русском языке',
280 | },
281 | ],
282 | db => {
283 | table => 'AppData',
284 | name => 'RLName',
285 | },
286 | format => 'capitalized'
287 | },
288 | {
289 | type => 'input',
290 | name => 'rufname',
291 | label => 'Имя',
292 | comment => 'Введите имя на русском языке так, как оно указано во внутреннем паспорте',
293 | example => 'Петр',
294 | check => 'zWЁ\s\-',
295 | check_logic => [
296 | {
297 | condition => 'english_only_for_not_rf_citizen',
298 | full_error => 'Для граждан РФ имя необходимо вводить на русском языке',
299 | },
300 | ],
301 | db => {
302 | table => 'AppData',
303 | name => 'RFName',
304 | },
305 | format => 'capitalized'
306 | },
307 | {
308 | type => 'input',
309 | name => 'rumname',
310 | label => 'Отчество',
311 | comment => 'Введите отчество на русском языке так, как оно указано во внутреннем паспорте',
312 | example => 'Петрович',
313 | check => 'WЁ\s\-',
314 | check_logic => [
315 | {
316 | condition => 'english_only_for_not_rf_citizen',
317 | full_error => 'Для граждан РФ отч необходимо вводить на русском языке',
318 | },
319 | {
320 | condition => 'free_only_if',
321 | table => 'AppData',
322 | name => 'NoRMName',
323 | error => 'Нет отчества',
324 | },
325 | ],
326 | db => {
327 | table => 'AppData',
328 | name => 'RMName',
329 | },
330 | format => 'capitalized'
331 | },
332 | {
333 | type => 'checkbox',
334 | name => 'no_rumname',
335 | label_for => 'нет отчества',
336 | db => {
337 | table => 'AppData',
338 | name => 'NoRMName',
339 | transfer => 'nope',
340 | },
341 | relation => {},
342 | },
343 | {
344 | type => 'free_line',
345 | },
346 | {
347 | type => 'input',
348 | name => 'birthdate',
349 | label => 'Дата рождения',
350 | comment => 'Введите дату рождения',
351 | example => '31.12.1900',
352 | check => $standart_date_check,
353 | complete_check => 'not_empty',
354 | check_logic => [
355 | {
356 | condition => 'now_or_earlier',
357 | },
358 | ],
359 | db => {
360 | table => 'AppData',
361 | name => 'BirthDate',
362 | },
363 | special => 'mask',
364 | },
365 | ],
366 |
367 | 'Данные загранпаспорта' => [
368 | {
369 | page_ord => 500,
370 | all_app_in_title => 1,
371 | progress => 5,
372 | page_db_id => 300005,
373 | },
374 | {
375 | type => 'input',
376 | name => 'rupassnum',
377 | label => '№ загранпаспорта',
378 | comment => 'Введите серию и номер паспорта как единый набор цифр без пробелов',
379 | example => '650000001',
380 | check => 'zWN',
381 | complete_check => 'not_empty',
382 | check_logic => [
383 | {
384 | condition => 'unique_in_pending',
385 | table => 'AppData',
386 | name => 'PassNum',
387 | },
388 | {
389 | condition => 'rf_pass_format',
390 | full_error => 'Неверный формат загранпаспорта. Гражданам РФ необходимо ввести серию и номер паспорта как единый набор цифр без пробелов и знака N',
391 | }
392 | ],
393 | db => {
394 | table => 'AppData',
395 | name => 'PassNum',
396 | },
397 | },
398 | {
399 | type => 'input',
400 | name => 'lname',
401 | label => 'Фамилия',
402 | comment => 'Введите фамилию на английском языке так, как она указана в загранпаспорте',
403 | example => 'Ivanov',
404 | check => 'zW\s\-',
405 | complete_check => 'not_empty',
406 | db => {
407 | table => 'AppData',
408 | name => 'LName',
409 | },
410 | format => 'capslock'
411 | },
412 | {
413 | type => 'input',
414 | name => 'fname',
415 | label => 'Имя',
416 | comment => 'Введите имя на английском языке так, как оно указано в загранпаспорте',
417 | example => 'Ivan',
418 | check => 'zW\s\-',
419 | complete_check => 'not_empty',
420 | db => {
421 | table => 'AppData',
422 | name => 'FName',
423 | },
424 | format => 'capslock'
425 | },
426 | {
427 | type => 'free_line',
428 | },
429 | {
430 | type => 'checkbox',
431 | name => 'ischild',
432 | label => 'Если ребёнок вписан в паспорт родителей',
433 | label_for => 'вписан в паспорт',
434 | check_logic => [
435 | {
436 | condition => 'younger_than',
437 | offset => 18,
438 | },
439 | ],
440 | db => {
441 | table => 'AppData',
442 | name => 'isChild',
443 | },
444 | relation => {},
445 | },
446 | ],
447 |
448 | 'Вы успешно добавили заявителя' => [
449 | {
450 | page_ord => 600,
451 | progress => 6,
452 | all_app_in_title => 1,
453 | replacer => '[app_finish]',
454 | page_db_id => 300006,
455 | },
456 | ],
457 |
458 | 'Выберите лицо на которое будет оформлен договор' => [
459 | {
460 | page_ord => 700,
461 | progress => 6,
462 | persons_in_page => 1,
463 | page_db_id => 300007,
464 | },
465 | {
466 | type => 'select',
467 | name => 'visa_text',
468 | label => 'Выберите на кого оформляется',
469 | check => 'zN-',
470 | db => {
471 | table => 'Appointments',
472 | name => 'PersonForAgreements',
473 | transfer => 'nope',
474 | },
475 | param => '[persons_in_app]',
476 | first_elements => 'default_free',
477 | },
478 | ],
479 |
480 | 'Укажите данные документа, удостоверяющего личность' => [
481 | {
482 | page_ord => 800,
483 | progress => 7,
484 | relation => {
485 | only_if_not => {
486 | table => 'Appointments',
487 | name => 'PersonForAgreements',
488 | value => '-1',
489 | }
490 | },
491 | page_db_id => 300008,
492 | },
493 | {
494 | type => 'text',
495 | name => 'rupass_text',
496 | label => 'Для граждан РФ необходимо указать данные внутреннего паспорта',
497 | },
498 | {
499 | type => 'free_line',
500 | },
501 | {
502 | type => 'info',
503 | name => 'info_rulname',
504 | label => 'Фамилия',
505 | db => {
506 | table => 'AppData',
507 | name => 'RLName',
508 | },
509 | },
510 | {
511 | type => 'info',
512 | name => 'info_rufname',
513 | label => 'Имя',
514 | db => {
515 | table => 'AppData',
516 | name => 'RFName',
517 | },
518 | },
519 | {
520 | type => 'info',
521 | name => 'info_rumname',
522 | label => 'Отчество',
523 | db => {
524 | table => 'AppData',
525 | name => 'RMName',
526 | },
527 | },
528 | {
529 | type => 'free_line',
530 | },
531 | {
532 | type => 'input',
533 | name => 'info_passnum',
534 | label => '№ паспорта',
535 | comment => 'Введите серию и номер паспорта как единый набор цифр без пробелов',
536 | example => '4510ХХХХХХ',
537 | check => 'zNW',
538 | db => {
539 | table => 'AppData',
540 | name => 'RPassNum',
541 | },
542 | },
543 | {
544 | type => 'input',
545 | name => 'info_passdate',
546 | label => 'Дата выдачи',
547 | comment => 'Введите дату выдачи, указанную в паспорте',
548 | example => '31.12.1900',
549 | check => $standart_date_check,
550 | check_logic => [
551 | {
552 | condition => 'now_or_earlier',
553 | },
554 | ],
555 | db => {
556 | table => 'AppData',
557 | name => 'RPWhen',
558 | },
559 | special => 'mask',
560 | },
561 | {
562 | type => 'input',
563 | name => 'info_rupasswhere',
564 | label => 'Кем выдан',
565 | comment => 'Укажите полное название выдавшей организации, так, как она указана в паспорте',
566 | example => 'ОВД по району Беговой города Москвы',
567 | check => 'zWЁN\s\-\_\.\,\;\'\"',
568 | db => {
569 | table => 'AppData',
570 | name => 'RPWhere',
571 | },
572 | },
573 | {
574 | type => 'input',
575 | name => 'info_address',
576 | label => 'Адрес регистрации',
577 | comment => 'Укажите адрес регистрации',
578 | example => 'г.Москва, М.Толмачевский пер., д. 6, стр.1',
579 | check => 'zWЁN\s\-\_\.\,\;\'\"',
580 | db => {
581 | table => 'AppData',
582 | name => 'RAddress',
583 | transfer => 'nope',
584 | },
585 | },
586 | {
587 | type => 'input',
588 | name => 'info_phone',
589 | label => 'Телефон',
590 | comment => 'Введите контактный телефон, сотовый или городской, с кодом оператора, без пробелов и разделителей',
591 | example => '79XXXXXXXXX',
592 | check => 'zN',
593 | db => {
594 | table => 'AppData',
595 | name => 'AppPhone',
596 | },
597 | },
598 | ],
599 |
600 | 'Укажите данные доверенного лица' => [
601 | {
602 | page_ord => 900,
603 | progress => 7,
604 | relation => {
605 | only_if => {
606 | table => 'Appointments',
607 | name => 'PersonForAgreements',
608 | value => '-1',
609 | }
610 | },
611 | page_db_id => 300009,
612 | },
613 | {
614 | type => 'input',
615 | name => 'dovlname',
616 | label => 'Фамилия',
617 | comment => 'Введите фамилию на русском языке так, как она указана во внутреннем паспорте',
618 | example => 'Иванов',
619 | check => 'zWЁ\s\-',
620 | db => {
621 | table => 'Appointments',
622 | name => 'LName',
623 | },
624 | },
625 | {
626 | type => 'input',
627 | name => 'dovfname',
628 | label => 'Имя',
629 | comment => 'Введите имя на русском языке так, как оно указана во внутреннем паспорте',
630 | example => 'Иван',
631 | check => 'zWЁ\s\-',
632 | db => {
633 | table => 'Appointments',
634 | name => 'FName',
635 | },
636 | },
637 | {
638 | type => 'input',
639 | name => 'dovmname',
640 | label => 'Отчество',
641 | comment => 'Введите отчество на русском языке так, как оно указана во внутреннем паспорте',
642 | example => 'Иванович',
643 | check => 'zWЁ\s\-',
644 | db => {
645 | table => 'Appointments',
646 | name => 'MName',
647 | },
648 | },
649 | {
650 | type => 'input',
651 | name => 'dovpassnum',
652 | label => '№ паспорта',
653 | comment => 'Введите серию и номер паспорта как единый набор цифр без пробелов',
654 | example => '4510ХХХХХХ',
655 | check => 'zNW',
656 | db => {
657 | table => 'Appointments',
658 | name => 'PassNum',
659 | },
660 | },
661 | {
662 | type => 'input',
663 | name => 'dovpassdate',
664 | label => 'Дата выдачи',
665 | comment => 'Введите дату выдачи, указанную в паспорте',
666 | example => '31.12.1900',
667 | check => $standart_date_check,
668 | check_logic => [
669 | {
670 | condition => 'now_or_earlier',
671 | },
672 | ],
673 | db => {
674 | table => 'Appointments',
675 | name => 'PassDate',
676 | },
677 | special => 'mask',
678 | },
679 | {
680 | type => 'input',
681 | name => 'dovpasswhere',
682 | label => 'Кем выдан',
683 | comment => 'Укажите полное название выдавшей организации, так, как она указана в паспорте',
684 | example => 'ОВД по району Беговой города Москвы',
685 | check => 'zWЁN\s\-\_\.\,\;\'\"',
686 | db => {
687 | table => 'Appointments',
688 | name => 'PassWhom',
689 | },
690 | },
691 | {
692 | type => 'input',
693 | name => 'dovaddress',
694 | label => 'Адрес',
695 | comment => 'Полный адрес, включая индекс',
696 | example => '119017, г.Москва, М.Толмачевский пер., д. 6, стр.1',
697 | check => 'zWЁN\s\-\_\.\,\;\'\"',
698 | db => {
699 | table => 'Appointments',
700 | name => 'Address',
701 | },
702 | },
703 | {
704 | type => 'input',
705 | name => 'dovphone',
706 | label => 'Телефон',
707 | comment => 'Введите контактный телефон, сотовый или городской, с кодом оператора, без пробелов и разделителей',
708 | example => '79161234567',
709 | check => 'zN',
710 | db => {
711 | table => 'Appointments',
712 | name => 'Phone',
713 | },
714 | },
715 | ],
716 |
717 | 'Оформление записи' => [
718 | {
719 | page_ord => 1000,
720 | progress => 8,
721 | persons_in_page => 1,
722 | page_db_id => 300010,
723 | },
724 | {
725 | type => 'text',
726 | name => 'appdate_text',
727 | label => 'Дата записи',
728 | font => 'bold',
729 | },
730 | {
731 | type => 'free_line',
732 | },
733 | {
734 | type => 'input',
735 | name => 'app_date',
736 | label => 'Дата записи в Визовый центр',
737 | comment => 'Введите дату, когда собираетесь посетить Визовый центр для подачи документов',
738 | check => $standart_date_check,
739 | check_logic => [
740 | {
741 | condition => 'now_or_later',
742 | },
743 | {
744 | condition => 'now_or_earlier',
745 | offset => 90,
746 | equality_is_also_fail => 1,
747 | full_error => 'Запись в Визовый центр более чем за [offset] не осуществляется',
748 | },
749 | ],
750 | db => {
751 | table => 'Appointments',
752 | name => 'AppDate',
753 | },
754 | special => 'datepicker, mask',
755 | uniq_code => 'onchange="update_timeslots(1);"',
756 | },
757 | {
758 | type => 'select',
759 | name => 'timeslot',
760 | label => 'Время',
761 | check => 'zN',
762 | db => {
763 | table => 'Appointments',
764 | name => 'TimeslotID',
765 | },
766 | param => '[free]',
767 | special => 'timeslots',
768 | },
769 | {
770 | type => 'free_line',
771 | },
772 | {
773 | type => 'free_line',
774 | },
775 | {
776 | type => 'text',
777 | name => 'services_text',
778 | label => 'СМС-оповещение о готовности документов ( платная услуга )',
779 | font => 'bold',
780 | },
781 | {
782 | type => 'free_line',
783 | },
784 | {
785 | type => 'input',
786 | name => 'sms',
787 | label => 'Номер телефона для
SMS-уведомления',
788 | comment => 'Введите номер сотового телефона для получения СМС о готовности документов; услуга платная, оставьте поле пустым, если в ней нет необходимости',
789 | example => '79XXXXXXXXX',
790 | check => 'N',
791 | check_logic => [
792 | {
793 | condition => 'length_strict',
794 | length => 11,
795 | full_error => 'Неправильный формат телефонного номера',
796 | }
797 | ],
798 | db => {
799 | table => 'Appointments',
800 | name => 'Mobile',
801 | },
802 | },
803 | {
804 | type => 'free_line',
805 | },
806 | {
807 | type => 'text',
808 | name => 'services_text',
809 | label => 'Доставка документов DHL ( платная услуга )',
810 | font => 'bold',
811 | },
812 | {
813 | type => 'free_line',
814 | },
815 | {
816 | type => 'input',
817 | name => 'ship_index',
818 | label => 'Индекс доставки',
819 | comment => 'Введите первые цифры индекса или первые буквы города для доставки документов; выберите из списка подходящий индекс и город; услуга платная, оставьте поле пустым, если в ней нет необходимости',
820 | example => '119017, Москва',
821 | check => 'ЁN\s\,\.\-\(\)',
822 | check_logic => [
823 | {
824 | condition => 'free_only_if_not',
825 | table => 'Appointments',
826 | name => 'ShAddress',
827 | error => 'Адрес доставки',
828 | }
829 | ],
830 | db => {
831 | table => 'Appointments',
832 | name => 'ShIndex',
833 | },
834 | special => 'post_index',
835 | },
836 | {
837 | type => 'input',
838 | name => 'shipping',
839 | label => 'Адрес доставки',
840 | comment => 'Введите адрес для доставки документов документов, без указания индекса и города; услуга платная, оставьте поле пустым, если в ней нет необходимости',
841 | example => 'Малый Толмачёвский пер., д.6 стр.1',
842 | check => 'ЁN\s\-\_\.\,\;\'\"',
843 | check_logic => [
844 | {
845 | condition => 'free_only_if_not',
846 | table => 'Appointments',
847 | name => 'ShIndex',
848 | error => 'Индекс доставки',
849 | },
850 | ],
851 | db => {
852 | table => 'Appointments',
853 | name => 'ShAddress',
854 | },
855 | },
856 | {
857 | type => 'free_line',
858 | },
859 | {
860 | type => 'text',
861 | name => 'services_text',
862 | label => 'Страхование ( платная услуга )',
863 | font => 'bold',
864 | },
865 | {
866 | type => 'free_line',
867 | },
868 | {
869 | type => 'include',
870 | place => 'in',
871 | template => 'insurance_form.tt2',
872 | }
873 | ],
874 |
875 | 'Предпочтительный офис получения готовых документов' => [
876 | {
877 | page_ord => 1100,
878 | progress => 9,
879 | relation => {
880 | only_if => {
881 | table => 'Appointments',
882 | name => 'CenterID',
883 | value => '1',
884 | }
885 | },
886 | page_db_id => 300011,
887 | },
888 | {
889 | type => 'radiolist',
890 | name => 'mezziwhom',
891 | label => 'Выберите офис, в котором будет осуществляться выдачи готовых документов',
892 | check => 'zN',
893 | db => {
894 | table => 'Appointments',
895 | name => 'OfficeToReceive',
896 | },
897 | param => {
898 | 1 => 'м.Третьяковская, Малый Толмачёвский пер., д.6 стр.1',
899 | 2 => 'м.Киевская, ул. Киевская, вл. 2, 3 этаж',
900 | },
901 | },
902 | ],
903 |
904 | 'Подтвердить запись' => [
905 | {
906 | page_ord => 1200,
907 | progress => 10,
908 | page_db_id => 300012,
909 | },
910 | {
911 | type => 'captcha',
912 | },
913 | ],
914 |
915 | 'Запись успешно создана!' => [
916 | {
917 | page_ord => 1300,
918 | progress => 11,
919 | page_db_id => 300013,
920 | },
921 | {
922 | type => 'text',
923 | name => 'conf_mail_text',
924 | label => 'На вашу почту отправлено письмо с подтверждением записи.',
925 | },
926 | {
927 | type => 'free_line',
928 | },
929 | {
930 | type => 'info',
931 | name => 'new_app_num',
932 | label => 'Номер записи',
933 | },
934 | {
935 | type => 'info',
936 | name => 'new_app_branch',
937 | label => 'Визовый центр',
938 | db => {
939 | table => 'Appointments',
940 | name => 'CenterID',
941 | },
942 | },
943 | {
944 | type => 'info',
945 | name => 'new_app_timedate',
946 | label => 'Дата',
947 | db => {
948 | table => 'Appointments',
949 | name => 'AppDate',
950 | },
951 | },
952 | {
953 | type => 'info',
954 | name => 'new_app_timeslot',
955 | label => 'Время записи',
956 | db => {
957 | table => 'Appointments',
958 | name => 'TimeslotID',
959 | },
960 | },
961 | ],
962 | };
963 | }
964 |
965 | 1;
966 |
--------------------------------------------------------------------------------
/scripts/autoform_clean.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use strict;
4 |
5 | use lib '/usr/local/www/data/htdocs/vcs/lib';
6 |
7 | use VCS::Config;
8 | use VCS::Vars;
9 | use VCS::SQL;
10 | use Data::Dumper;
11 |
12 |
13 | log_file();
14 | log_file("включение скрипта очистки autotoken");
15 | log_file("///////////////////////////////////");
16 |
17 | my $vars = new VCS::Vars(qw( VCS::Config VCS::SQL ));
18 |
19 | $vars->db->db_connect( $vars );
20 |
21 | my ( $clear, $first_step, $softban_stat ) = ( 0, 0, 0 );
22 |
23 | # ///////////////
24 |
25 | $softban_stat = $vars->db->sel1("
26 | SELECT COUNT(ID) FROM SoftBan_stat
27 | WHERE DATEDIFF(now(), IPDate) >= 1"
28 | );
29 |
30 | $vars->db->query("
31 | DELETE FROM SoftBan_stat WHERE DATEDIFF(now(), IPDate) > 1"
32 | );
33 |
34 | # ///////////////
35 |
36 | $first_step = $vars->db->sel1("
37 | SELECT count(ID) FROM AutoToken
38 | WHERE LinkSended IS NULL AND CreatedApp IS NULL AND Finished = 0
39 | AND DATEDIFF(now(), StartDate) > 1"
40 | );
41 |
42 | $vars->db->query("
43 | DELETE FROM AutoToken
44 | WHERE LinkSended IS NULL AND CreatedApp IS NULL AND Finished = 0
45 | AND DATEDIFF(now(), StartDate) > 1"
46 | );
47 |
48 | # ///////////////
49 |
50 | my $alltokens = $vars->db->selallkeys("
51 | SELECT ID, StartDate, LastChange, EMail, LastIP, Token, AutoAppID, Finished
52 | FROM AutoToken
53 | WHERE CreatedApp IS NULL AND Finished = 0
54 | AND DATEDIFF(now(), StartDate) > 14 AND DATEDIFF(now(), LastChange) > 3"
55 | );
56 |
57 | my $alltokens_count = scalar( @$alltokens );
58 |
59 | # ///////////////
60 |
61 | my $completed_tokens = $vars->db->selallkeys("
62 | SELECT AutoToken.ID, StartDate, LastChange, AutoToken.EMail, LastIP, Token, AutoAppID, Finished
63 | FROM AutoToken
64 | JOIN Appointments ON CreatedApp = Appointments.ID
65 | WHERE Finished = 1 AND AutoAppID IS NOT NULL
66 | AND DATEDIFF(now(), AppDate) > 90"
67 | );
68 |
69 | my $completed_tokens_count = scalar( @$completed_tokens );
70 |
71 | for my $token ( @$alltokens, @$completed_tokens ) {
72 |
73 | if ( !$token->{ Finished } ) {
74 |
75 | $vars->db->query("
76 | INSERT INTO AutoToken_expired (Token, LastIP, EMail, StartDate, LastChange, RemovedDate) VALUES (?, ?, ?, ?, ?, now())", {},
77 | $token->{ Token }, $token->{ LastIP }, $token->{ EMail }, $token->{ StartDate }, $token->{ LastChange }
78 | );
79 |
80 | $vars->db->query("
81 | DELETE FROM AutoToken WHERE ID = ?", {}, $token->{ ID }
82 | );
83 | }
84 |
85 | $clear += 1;
86 |
87 | next if $token->{ AutoAppID } == 0 or !defined( $token->{ AutoAppID } );
88 |
89 | $vars->db->query("
90 | UPDATE AutoToken SET AutoAppID = NULL, AutoAppDataID = NULL, AutoSchengenAppDataID = NULL, AutoSpbDataID = NULL
91 | WHERE Token = ?", {}, $token->{ Token }
92 |
93 | ) if $token->{ Finished };
94 |
95 | $vars->db->query("
96 | DELETE FROM AutoAppointments WHERE ID = ?", {}, $token->{ AutoAppID }
97 | );
98 |
99 | my $alldata = $vars->db->selallkeys("
100 | SELECT ID, SchengenAppDataID FROM AutoAppData WHERE AppID = ?",
101 | $token->{ AutoAppID }
102 | );
103 |
104 | for my $data ( @$alldata ) {
105 |
106 | $vars->db->query("
107 | DELETE FROM AutoAppData WHERE ID = ?", {}, $data->{ ID }
108 | );
109 |
110 | $vars->db->query("
111 | DELETE FROM AutoSpbAlterAppData WHERE AppDataID = ?", {}, $data->{ ID }
112 | );
113 |
114 | $vars->db->query("
115 | DELETE FROM AutoSchengenAppData WHERE ID = ?", {}, $data->{ SchengenAppDataID }
116 | );
117 | }
118 | }
119 |
120 | log_file( "всего старых записей статистики softban удалено: $softban_stat" );
121 | log_file( "всего однодневок удалено: $first_step" );
122 | log_file( "всего старых очищено: $clear" );
123 | log_file( "- из них незаконченных через 14 дней: $alltokens_count" );
124 | log_file( "- из них законченных через 90 дней: $completed_tokens_count" );
125 | log_file( "скрипт завершился" );
126 |
127 |
128 |
129 | sub log_file
130 | {
131 | my $msg = shift;
132 |
133 | my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime( time );
134 |
135 | $year += 1900;
136 | $mon++;
137 |
138 | for ( $sec, $min, $hour, $mday, $mon, $year) {
139 |
140 | $_ = "0$_" if $_ < 10;
141 | };
142 |
143 | open my $file_log, '>>', '/var/log/autotoken_del.log';
144 |
145 | print $file_log "$year-$mon-$mday $hour:$min:$sec $msg\n";
146 |
147 | close $file_log;
148 | };
149 |
--------------------------------------------------------------------------------
/scripts/autoform_fox.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | use strict;
3 |
4 | use LWP::Simple;
5 | use XML::Simple;
6 | use Data::Dumper;
7 | use Date::Calc;
8 | use Cwd "abs_path";
9 |
10 | use lib '/usr/local/www/data/htdocs/vcs/lib';
11 |
12 | use VCS::Config;
13 | use VCS::Vars;
14 | use VCS::SQL;
15 | use VCS::System;
16 | use VCS::Memcache;
17 | use VCS::AdminFunc;
18 | use VCS::Site::autopayment;
19 | use VCS::Site::autodata;
20 |
21 |
22 | log_file();
23 | log_file("Включение скрипта");
24 | log_file("/////////////////");
25 |
26 | my $vars = new VCS::Vars(qw( VCS::Config VCS::SQL VCS::System VCS::Memcache VCS::AdminFunc ));
27 |
28 | $vars->db->db_connect( $vars );
29 |
30 | my $all_docs_in_fox_status = $vars->db->selallkeys("
31 | SELECT DocPack.ID, DocPack.AgreementNo, AutoRemote.FoxIDto FROM DocPack
32 | JOIN AutoRemote ON DocPack.AppID = AutoRemote.AppID
33 | WHERE PStatus = 27
34 | ");
35 |
36 | for my $doc ( @$all_docs_in_fox_status ) {
37 |
38 | log_file( "запрос: $doc->{ AgreementNo } ( квитанция $doc->{ FoxIDto } )" );
39 |
40 | my $status = VCS::Site::autopayment::fox_status( $vars, $doc->{ FoxIDto } );
41 |
42 | log_file( "статус: $status" );
43 |
44 | if ( $status eq "Груз доставлен" ) {
45 |
46 | log_file( "-----> " . close_doc( $vars, $doc->{ ID }, $doc->{ AgreementNo } ) );
47 |
48 | log_file( "-----> " . close_app( $vars, $doc->{ ID } ) );
49 | }
50 | }
51 |
52 | log_file( "Скрипт выключен" );
53 |
54 |
55 |
56 | sub close_doc {
57 |
58 | my ( $vars, $doc_id, $agr ) = @_;
59 |
60 | my $doc_lists = $vars->db->selallkeys("
61 | SELECT DocPackList.ID, PassNum, CBankID FROM DocPackList
62 | JOIN DocPackInfo ON DocPackList.PackInfoID = DocPackInfo.ID
63 | WHERE DocPackInfo.PackID = ? AND DocPackList.Status != 7",
64 | $doc_id
65 | );
66 |
67 | $vars->db->{ dbh }->do( "UPDATE DocPack SET PStatus = 6 WHERE ID = ?", {}, $doc_id );
68 |
69 | for ( @$doc_lists ) {
70 |
71 | $vars->db->{ dbh }->do( "UPDATE DocPackList SET Status = 6 WHERE ID = ?", {}, $_->{ ID } );
72 |
73 | $vars->db->{ dbh }->do( "
74 | INSERT INTO DocHistory (DocID, PassNum, Login, HDate, StatusID, BankID )
75 | VALUES ( ?, ?, ?, now(), 6, ? )", {},
76 | $doc_id, $_->{ PassNum }, 'remote_script', $_->{ CBankID } );
77 | }
78 |
79 | return $agr;
80 | }
81 |
82 | sub close_app {
83 |
84 | my ( $vars, $doc_id ) = @_;
85 |
86 | my $app_id = $vars->db->sel1( "SELECT AppID FROM DocPack WHERE ID = ?", $doc_id );
87 |
88 | my $app_num = $vars->db->sel1( "SELECT AppNum FROM Appointments WHERE ID = ?", $app_id );
89 |
90 | $vars->db->{ dbh }->do( "UPDATE AppData SET Status = 4 WHERE AppID = ? AND Status != 2", {}, $app_id );
91 |
92 | return $app_num;
93 | }
94 |
95 | sub log_file {
96 |
97 | my $msg = shift || '';
98 |
99 | my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime( time );
100 | $year += 1900; $mon++;
101 |
102 | for ( $sec, $min, $hour, $mday, $mon, $year ) {
103 | $_ = '0'.$_ if $_ < 10;
104 | };
105 |
106 | open my $file_log, '>>', '/var/log/autoform_fox.log';
107 |
108 | print $file_log "$year-$mon-$mday $hour:$min:$sec " . $msg . "\n";
109 |
110 | close $file_log;
111 | }
112 |
--------------------------------------------------------------------------------
/scripts/autoform_softban.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use LWP::Simple;
4 | use XML::Simple;
5 | use Data::Dumper;
6 | use Cwd "abs_path";
7 | use strict;
8 |
9 | use lib '/usr/local/www/data/htdocs/vcs/lib';
10 |
11 | use VCS::Config;
12 | use VCS::Vars;
13 | use VCS::SQL;
14 | use VCS::System;
15 | use VCS::Memcache;
16 | use VCS::AdminFunc;
17 | use Date::Calc;
18 |
19 | my $log_name = '/var/log/autoform_softban.log';
20 |
21 | my $warn_connection = 50;
22 |
23 | my $inner_ip = {
24 | '127.0.0.1' => 1,
25 | };
26 |
27 | log_file();
28 | log_file("Включение скрипта подавления подозрительной активности");
29 | log_file("//////////////////////////////////////////////////////");
30 |
31 | my $vars = new VCS::Vars(qw( VCS::Config VCS::SQL VCS::System VCS::Memcache VCS::AdminFunc ));
32 |
33 | $vars->db->db_connect($vars);
34 |
35 | my $already_banned_array = $vars->db->selallkeys("
36 | SELECT IP FROM SoftBan
37 | ");
38 |
39 | my %already_banned = map { $_->{ IP } => 1 } @$already_banned_array;
40 |
41 | my $connections = $vars->db->selallkeys("
42 | SELECT LastIP AS IP, count(ID) AS ConnectionNumber, MIN(StartDate) AS Start, MAX(StartDate) AS End
43 | FROM AutoToken
44 | WHERE DATE(StartDate) = CURDATE() AND Email IS NULL
45 | GROUP BY LastIP ORDER BY ConnectionNumber DESC;
46 | ");
47 |
48 | for my $row ( @$connections ) {
49 |
50 | next if $row->{ ConnectionNumber } < $warn_connection;
51 |
52 | next if $already_banned{ $row->{ IP } };
53 |
54 | next if exists $inner_ip->{ $row->{ IP } };
55 |
56 | $vars->db->query("
57 | INSERT INTO SoftBan (IP, BanDate, Reason) VALUES (?, now(), ?)",
58 | {}, $row->{ IP }, "autoform empty forms"
59 | );
60 |
61 | log_file( $row->{ IP } . " --> " . $row->{ ConnectionNumber } );
62 | }
63 |
64 | log_file( "Скрипт выключен" );
65 |
66 |
67 | sub log_file {
68 |
69 | my $msg = shift || '';
70 |
71 | my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime( time );
72 | $year += 1900; $mon++;
73 |
74 | for ( $sec, $min, $hour, $mday, $mon, $year ) {
75 | $_ = '0'.$_ if $_ < 10;
76 | };
77 |
78 | open my $file_log, '>>', $log_name;
79 |
80 | print $file_log "$year-$mon-$mday $hour:$min:$sec " . $msg . "\n";
81 |
82 | close $file_log;
83 | }
84 |
--------------------------------------------------------------------------------
/scripts/autoform_softban_warn.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use LWP::Simple;
4 | use XML::Simple;
5 | use Data::Dumper;
6 | use Cwd "abs_path";
7 | use strict;
8 |
9 | use lib '/usr/local/www/data/htdocs/vcs/lib';
10 |
11 | use VCS::Config;
12 | use VCS::Vars;
13 | use VCS::SQL;
14 | use VCS::System;
15 | use VCS::Memcache;
16 | use VCS::AdminFunc;
17 | use Date::Calc;
18 |
19 | my $log_name = '/var/log/autoform_softban_warn.log';
20 |
21 | my @addresses = (
22 | 'mail@mail.com',
23 | );
24 |
25 | my $signature =
26 | 'С уважением,
Скрипт отчёта о подозрительной активности';
27 |
28 | log_file();
29 | log_file("Включение скрипта проверки заблокированной активности");
30 | log_file("/////////////////////////////////////////////////////");
31 |
32 | my $vars = new VCS::Vars(qw( VCS::Config VCS::SQL VCS::System VCS::Memcache VCS::AdminFunc ));
33 |
34 | $vars->db->db_connect($vars);
35 |
36 | my $connections = $vars->db->selallkeys("
37 | SELECT IP, BanDate, Reason FROM SoftBan
38 | WHERE DATE(BanDate) = (CURDATE() - INTERVAL 1 DAY) ORDER BY BanDate
39 | ");
40 |
41 | my $table = create_table( $connections );
42 |
43 | unless ( defined $table ) {
44 |
45 | log_file( "Ничего подозрительного НЕ было" );
46 | }
47 | else {
48 | my $subject = 'Отчёт о подавлении подозрительной внешней активности';
49 | my $body = $table . "
Данные за прошедшие сутки
Все указанные адреса заблокированы
" . $signature;
50 |
51 | for ( @addresses ) {
52 | $vars->get_system->send_mail( $vars, $_, $subject, $body );
53 | log_file( "Отправлено сообщение на $_" );
54 | }
55 | }
56 |
57 | log_file( "Скрипт выключен" );
58 |
59 |
60 |
61 | sub log_file {
62 | my $msg = shift || '';
63 | my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime( time );
64 | $year += 1900; $mon++;
65 | for ( $sec, $min, $hour, $mday, $mon, $year ) {
66 | $_ = '0'.$_ if $_ < 10;
67 | };
68 |
69 | open my $file_log, '>>', $log_name;
70 | print $file_log "$year-$mon-$mday $hour:$min:$sec " . $msg . "\n";
71 | close $file_log;
72 | }
73 |
74 | sub create_table {
75 |
76 | my $connections = shift;
77 |
78 | my $table = '
$_ | " for ( @heads ); 90 | 91 | $table .= "
" . $row->{ $column } . " | "; 106 | } 107 | 108 | $table .= "
17 |
19 |
22 | [%app_tx%]
21 |
24 |
49 |
27 |
30 | [%date_time%] 29 |
33 |
36 | [%app_num%] 35 |
39 |
42 | [%app_person%] 41 |[%list_tx%]
45 | [%app_list%] 47 |
50 |
54 |
55 | [%dis_head%]
57 | 56 | [%dis_tx%]
58 |
60 | [%no_reply_head%] 59 | [%no_reply%] |
61 |
63 | ![]() [%branch_tx%]
68 |
73 | Website: [%app_website%] 76 | 78 | [%info_btn%] [%resh_btn%] 90 | [%canc_btn%] 96 | [%prnt_btn%] 102 | [%edit_app_button%] 103 | |
104 |
108 | 109 | | 110 |
37 | [% langreq('Статус рассмотрения Ваших документов') %]: 38 | |